2017-04-02 78 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); 

然后,您可以在这里放置一个断点,看看解串器给你。