2017-04-02 77 views
-1

這是我的類無法反序列化我的json

最初的一個實際上需要轉換爲良好的json數據。 這是最初的壞

{ 
    "channels": { 
     "heart-rate": { 
      "events": { 
       "$type": "System.Collections.Generic.List`1[[Project.Model.Activity+Channel+Event, Project]], mscorlib", 
       "$values": [{ 
         "$type": "Project.Model.ChannelEvents.HeartRateChannelEvent, LTF.MyPlan.ActivityUtil", 
         "beatsPerMinute": 40, 
         "offset": 0 
        } 
       ] 
      } 
     }, 
     "location": { 
      "events": { 
       "$type": "System.Collections.Generic.List`1[[Project.Model.Activity+Channel+Event, Project]], mscorlib", 
       "$values": [{ 
         "$type": "Project.Model.ChannelEvents.LocationChannelEvent, Project", 
         "latitude": 0.0, 
         "longitude": 0.0, 
         "offset": 0 
        } 
       ] 
      } 
     } 
    } 
} 

public class LocationChannelEvent : Activity.Channel.Event  
{ 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 
    public float? Distance { get; set; } 
    public float? Altitude { get; set; } 

    /// <summary> 
    /// Speed in m/s 
    /// </summary> 
    public float? Speed { get; set; } 

這是我的JSON數據,這我無法反序列化。我不斷收到默認值,甚至當我改變

{ 


"location": { 
      "events": { 
       "$type": "System.Collections.Generic.List`1[[Project.Model.Activity+Channel+Event, Project]], mscorlib", 
       "$values": [{ 
         "$type": "Project.Model.ChannelEvents.LocationChannelEvent, Project", 
         "latitude": 0.0, 
         "longitude": 0.0, 
         "offset": 0 
      ] 
     } 
    } 
} 

我的自定義Coverter

public class CompactListConverter : JsonConverter 
    { 
     public const string TypeKey = "type"; 
     public const string StructureKey = "structure"; 
     public const string ListKey = "list"; 

    /// <summary> 
    /// Only convert lists of non-enumerable class types. 
    /// </summary> 
    /// <param name="objectType"></param> 
    /// <returns></returns> 
    public override bool CanConvert(Type objectType) 
    { 
     var objectTypeInfo = objectType.GetTypeInfo(); 

     if (objectTypeInfo.IsGenericType && objectType.GetGenericTypeDefinition() == typeof(List<>)) 
     { 
      var itemTypeInfo = objectTypeInfo.GenericTypeArguments.Single().GetTypeInfo(); 
      if (itemTypeInfo.IsClass && !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(itemTypeInfo)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

    /// <summary> 
    /// Generates a wrapper object containing type, structure, and the condensed list. 
    /// </summary> 
    /// <param name="writer"></param> 
    /// <param name="value"></param> 
    /// <param name="serializer"></param> 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var list = (IList)value; 
     if (list.Count > 0) 
     { 
      var array = new JArray(); 
      var wrapper = GetWrapper(list, serializer); 

      foreach (var item in list) 
      { 
       var obj = JObject.FromObject(item, serializer); 
       var itemValues = new JArray(); 
       foreach (var prop in obj.Properties()) 
       { 
        itemValues.Add(prop.Value); 
       } 
       array.Add(itemValues); 
      } 

      wrapper.Add(ListKey, array); 
      wrapper.WriteTo(writer); 
     } 
     else 
     { 
      new JObject().WriteTo(writer); 
     } 
    } 

    private JObject GetWrapper(IList list, JsonSerializer serializer) 
    { 
     var wrapper = new JObject {{TypeKey, list[0].GetType().AssemblyQualifiedName}}; 

     var keys = new JArray(); 

     var first = JObject.FromObject(list[0], serializer); 
     foreach (var prop in first.Properties()) 
     { 
      keys.Add(new JValue(prop.Name)); 
     } 

     wrapper.Add(StructureKey, keys); 

     return wrapper; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var wrapper = JObject.Load(reader); 
     var itemType = Type.GetType(wrapper.GetValue(TypeKey).ToObject<string>()); 
     var array = wrapper.GetValue(ListKey) as JArray; 

     var list = existingValue as IList ?? (IList) Activator.CreateInstance(typeof (List<>).MakeGenericType(new[] {itemType})); 

     if (array != null && array.Count > 0) 
     { 
      var keys = wrapper.GetValue(StructureKey) as JArray ?? new JArray(); 
      foreach (var itemValues in array.Children<JArray>()) 
      { 
       var item = new JObject(); 
       for (var i = 0; i < keys.Count; i++) 
       { 
        item.Add(new JProperty(keys[i].ToString(), itemValues[i])); 
       } 

       list.Add(item.ToObject(itemType, serializer)); 
      } 
     } 
     return list; 
    } 
} 


public class ChannelCompactingConverter : CompactListConverter 
    { 
     public override bool CanConvert(Type objectType) 
     { 
      return base.CanConvert(objectType) 
       && typeof(IList<Activity.Channel.Event>).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); 
     } 
    } 
+0

沒有理由說它會起作用。使用例如[tag:json.net],如果你看[docs](http://www.newtonsoft.com/json/help/html/SerializationGuide.htm),你會發現你的JSON應該看起來像**如果您啓用['TypeNameHandling'](http://www.newtonsoft.com/json/help/html/),則可以從[原始問題](https://stackoverflow.com/q/43145603/3744182)獲取badjson ** SerializeTypeNameHandling.htm)。爲什麼不直接反序列化** badjson **而不改變它? – dbc

+0

我到底在哪裏使用這個。 typenamehandling-我應該創建一個新的反序列化類 – kishore

+0

您是否問過如何直接反序列化您的** badjson **而不改變它? – dbc

回答

1

只要您使用custom JsonConverer,您可以使用反編譯並重新序列化List<LocationChannelEvent>,格式如圖所示。這是必需的,因爲默認情況下,對象集合是從JSON數組序列化的,但在JSON中,對象集合正在序列化爲稍微更緊湊的單個對象形式,其中對象屬性名稱被序列化在名爲"structure"的字符串數組中只有一次,並且對象本身表示爲值數組的數組,內部數組與結構數組1-1對應。

因此,如果您創建以下轉換器:

public class StructuredListConverter<T> : JsonConverter 
{ 
    const string typeName = "type"; 
    const string structureName = "structure"; 
    const string listName = "list"; 

    public override bool CanConvert(Type objectType) 
    { 
     if (!typeof(ICollection<T>).IsAssignableFrom(objectType)) 
      return false; 
     // This converter is only implemented for read/write collections. So no arrays. 
     if (objectType.IsArray) 
      return false; 
     return true; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
      return null; 
     var collection = existingValue as ICollection<T> ?? (ICollection<T>) serializer.ContractResolver.ResolveContract(objectType).DefaultCreator(); 
     var root = JObject.Load(reader); 
     var structure = root[structureName] == null ? null : root[structureName].ToObject<string []>(); 
     if (structure == null) 
      throw new JsonSerializationException("structure not found."); 
     var listToken = root[listName]; 
     if (listToken == null || listToken.Type == JTokenType.Null) 
      return collection; 
     var list = listToken as JArray; 
     if (list == null) 
      throw new JsonSerializationException("list was not an array."); 
     if (list == null || list.Count == 0) 
      return collection; 
     foreach (var item in list) 
     { 
      if (item == null || item.Type == JTokenType.Null) 
       collection.Add(default(T)); 
      else if (item.Type != JTokenType.Array) 
       throw new JsonSerializationException(string.Format("Item was not an array: {0}", item)); 
      else 
       collection.Add(new JObject(item.Zip(structure, (i, n) => new JProperty(n, i))).ToObject<T>()); 
     } 
     return collection; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var contract = serializer.ContractResolver.ResolveContract(typeof(T)) as JsonObjectContract; 
     if (contract == null) 
      throw new JsonSerializationException(string.Format("Type {0} is not mapped to a JSON object.", typeof(T))); 

     var collection = (ICollection<T>)value; 
     writer.WriteStartObject(); 

     // Write item type 
     writer.WritePropertyName(typeName); 
     serializer.Serialize(writer, typeof(T)); 

     // Write structure (property names) 
     var structure = contract.Properties.Where(p => p.Readable && !p.Ignored).Select(p => p.PropertyName).ToList(); 
     writer.WritePropertyName(structureName); 
     serializer.Serialize(writer, structure); 

     // Write array of array of values 
     var query = collection 
      .Select(i => i == null ? null : contract.Properties.Where(p => p.Readable && !p.Ignored).Select(p => p.ValueProvider.GetValue(i))); 
     writer.WritePropertyName(listName); 
     serializer.Serialize(writer, query); 

     writer.WriteEndObject(); 
    } 
} 

,並定義你的數據模型如下:

public class LocationChannelEvent : Activity.Channel.Event 
{ 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 
    public float? Distance { get; set; } 
    public float? Altitude { get; set; } 

    /// <summary> 
    /// Speed in m/s 
    /// </summary> 
    public float? Speed { get; set; } 
} 

public class Location 
{ 
    [JsonConverter(typeof(StructuredListConverter<LocationChannelEvent>))] 
    public List<LocationChannelEvent> events { get; set; } 
} 

public class RootObject 
{ 
    public Location location { get; set; } 
} 

您將能夠反序列化和顯示的JSON重新序列化。

原型fiddle

+0

我們有一個自定義轉換器已經內置Utility.Let我添加到問題 – kishore

+0

@ kishore - 這是一個完全不同的問題,我上面的所有工作似乎都浪費時間。您需要調試您的轉換器以確定問題所在。如果你不能確定問題,然後問。看到https://stackoverflow.com/help/how-to-ask – dbc

+0

對不起,我的轉換器工作正常,但一些數據已損壞,就像我顯示爲壞的json數據一樣。 – kishore

0

那麼就我熟悉的JSON這兩樣東西類和JSON是兩個完全不同的事情!所以很明顯,它不能像那樣序列化。

我在這種情況下所做的是,我將json反序列化爲dynamic對象,然後查看C#創建的對象並將其與我的類進行比較。你可以做同樣的事情是這樣的:

dynamic res = JsonConvert.Deserialize(json); 

然後,您可以在這裏放置一個斷點,看看解串器給你。