2015-10-15 44 views
2

我有一個屬性IReadOnlyList<RoadLaneDto>類型。爲了與其他地方兼容,我將其更改爲RoadLaneDto[]。現在,當我反序列化我的舊數據,我得到這個錯誤:

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的建議而不是要求?我可以寫一個可以處理這種情況的自定義轉換器嗎?

+0

你可以在序列化對象的位置顯示一些代碼,什麼是JSON數據和相應的目標類型。我想你可以擴展JSON序列化器來處理這種自定義映射。 – vendettamit

回答

1

一般來說,我不推薦序列化集合類型,正是出於這個原因:您想要自由地更改集合類型(儘管不一定是集合類型條目),而沒有序列化問題。如果要實現具有與Json.NET默認值不同的特定集合類型的集合接口值屬性,請爲ICollection<T>指定一個HashSet<T>,您可以在包含類的默認構造函數中分配它,並且Json.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確實支持多維數組,因此擴展對> 1的數組的支持是可能的。