这是我的课
最初的一个实际上需要转换为良好的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 ] } } }
我的自定义封面
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()); } }
您可以使用json.net以List<LocationChannelEvent>显示的格式对a进行反序列化和重新序列化,只要您使用custom即可JsonConverer。这是必需的,因为默认情况下,对象集合在JSON数组之间进行序列化,但是在JSON中,对象集合以单个对象的紧凑形式进行序列化,其中对象属性名称已序列化在称为的字符串数组中仅出现一次"structure",并且对象本身表示为值数组,内部数组与结构数组成1-1对应。
List<LocationChannelEvent>
JsonConverer
"structure"
因此,如果您创建以下转换器:
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。
原型小提琴。