使Json.NET不兼容$ type [英] make Json.NET ignore $type if it's incompatible
问题描述
我有一个IReadOnlyList<RoadLaneDto>
类型的属性.为了与其他地方兼容,我将其更改为RoadLaneDto[]
.现在,当我反序列化旧数据时,会出现以下错误:
I had a property of type IReadOnlyList<RoadLaneDto>
. To be compatible elsewhere, I changed it to RoadLaneDto[]
. Now, when I deserialize my old data, I get this error:
Newtonsoft.Json.JsonSerializationException:在JSON'System.Collections.Generic.List`1 [[Asi.Shared.Interfaces.DTOs.Map.RoadLaneDto,Asi.Shared.Interfaces,Version = 1.0.0.0,文化中指定的类型= neutral,PublicKeyToken = null]],mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'与'Asi.Shared.Interfaces.DTOs.Map.RoadLaneDto [],Asi.Shared.Interfaces,版本= 1.0.0.0,文化=中性,PublicKeyToken =空".路径"Shapes [0] .Lanes.$ type",第78行,位置132.
Newtonsoft.Json.JsonSerializationException : Type specified in JSON 'System.Collections.Generic.List`1[[Asi.Shared.Interfaces.DTOs.Map.RoadLaneDto, Asi.Shared.Interfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not compatible with 'Asi.Shared.Interfaces.DTOs.Map.RoadLaneDto[], Asi.Shared.Interfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Path 'Shapes[0].Lanes.$type', line 78, position 132.
什么是使它们兼容的正确方法?我可以提出$type
的建议而不是要求吗?我可以编写某种自定义转换器来处理这种情况吗?
What is the right approach to make these compatible? Can I make the $type
a suggestion rather than a requirement? Can I write a custom converter of some kind that would handle this situation?
推荐答案
通常,出于以下原因,我不建议序列化集合类型:您想自由更改集合的类型(尽管不一定要更改类型)集合 item )而没有序列化问题.如果要使用与Json.NET的默认值不同的特定集合类型来实现集合接口值属性,例如将HashSet<T>
表示为ICollection<T>
,则可以在包含类的默认构造函数中分配它,并且Json.NET将使用预分配的集合.要仅序列化对象类型而不序列化集合类型,请设置 TypeNameHandling = TypeNameHandling.Objects
.
In general I don't recommend serializing collection types, for precisely this reason: you want to be free to change the type of collection (though not necessarily the type of collection item) without serialization problems. If you want to implement a collection-interface-valued property with a specific collection type that differs from Json.NET's defaults, say a HashSet<T>
for an ICollection<T>
, you can allocate it in the default constructor of the containing class, and Json.NET will use the pre-allocated collection. To serialize only object types and not collection types, set TypeNameHandling = TypeNameHandling.Objects
.
话虽如此,以下转换器在反序列化第1级数组时将吞下类型信息.
That being said, the following converter will swallow type information when deserializing an array of rank 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();
}
}
然后您可以像使用它一样
Then you can use it like:
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; }
}
或者,您可以在设置中全局使用转换器,并使其包含所有阵列的类型信息:
Or, you can use the converter globally in settings and have it swallow type information for all arrays:
var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new IgnoreArrayTypeConverter() }, TypeNameHandling = TypeNameHandling.All };
Json.NET确实支持多维数组,因此可以将支持扩展到等级大于1的数组.
Json.NET does support multidimensional arrays so extending support to arrays of rank > 1 would be possible.
这篇关于使Json.NET不兼容$ type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!