Json.. NET忽略$type,如果它'不兼容

本文关键字:不兼容 如果 NET 忽略 type Json | 更新日期: 2023-09-27 18:17:52

我有一个类型为IReadOnlyList<RoadLaneDto>的属性。为了在其他地方兼容,我将其更改为RoadLaneDto[]。现在,当我反序列化旧数据时,我得到了这个错误:

Newtonsoft.Json。JsonSerializationException:在JSON 'System.Collections.Generic.List ' 1中指定的类型。RoadLaneDto Asi.Shared。[. interface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'与' asia . shared .Interfaces. dtos . map . '不兼容。Asi.Shared RoadLaneDto[]。接口,版本=1.0.0.0,文化=中性,PublicKeyToken=null'。路径的形状[0].Lanes。$type',第78行,第132位

使它们兼容的正确方法是什么?我可以把$type作为建议而不是要求吗?我可以编写某种自定义转换器来处理这种情况吗?

Json.. NET忽略$type,如果它'不兼容

一般来说,我不建议序列化集合类型,原因正是:您希望能够自由地更改集合的类型(尽管不一定是集合item的类型),而不会出现序列化问题。如果您希望实现具有不同于Json的特定集合类型的集合接口值属性。. NET的默认值,例如ICollection<T>HashSet<T>,您可以在包含类的默认构造函数中分配它。. NET将使用预分配的集合。如果只序列化对象类型而不序列化集合类型,请设置TypeNameHandling = TypeNameHandling.Objects

话虽如此,以下转换器将在反序列化秩为1的数组时吞下类型信息:

public class IgnoreArrayTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsArray && objectType.GetArrayRank() == 1 && objectType.HasElementType;
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (!CanConvert(objectType))
            throw new JsonSerializationException(string.Format("Invalid type '"{0}'"", objectType));
        if (reader.TokenType == JsonToken.Null)
            return null;
        var token = JToken.Load(reader);
        var itemType = objectType.GetElementType();
        return ToArray(token, itemType, serializer);
    }
    private static object ToArray(JToken token, Type itemType, JsonSerializer serializer)
    {
        if (token == null || token.Type == JTokenType.Null)
            return null;
        else if (token.Type == JTokenType.Array)
        {
            var listType = typeof(List<>).MakeGenericType(itemType);
            var list = (ICollection)token.ToObject(listType, serializer);
            var array = Array.CreateInstance(itemType, list.Count);
            list.CopyTo(array, 0);
            return array;
        }
        else if (token.Type == JTokenType.Object)
        {
            var values = token["$values"];
            if (values == null)
                return null;
            return ToArray(values, itemType, serializer);
        }
        else
        {
            throw new JsonSerializationException("Unknown token type: " + token.ToString());
        }
    }
    public override bool CanWrite { get { return false; } }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

那么你可以这样使用:

public class RootObject
{
    [JsonProperty(TypeNameHandling = TypeNameHandling.None)] // Do not emit array type information
    [JsonConverter(typeof(IgnoreArrayTypeConverter))]        // Swallow legacy type information
    public string[] Lanes { get; set; }
}

或者,您可以在设置中全局使用转换器,并让它接收所有数组的类型信息:

    var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new IgnoreArrayTypeConverter() }, TypeNameHandling = TypeNameHandling.All };

Json。. NET支持多维数组,因此可以扩展对rank> 1的数组的支持。