如何从.NET数据结构创建“锯齿状”对象的JSON数组

作为LINQ-to-Entities投影的结果,我最终得到了一个List ,如下所示,我手动创建它:

 List data = new List(); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g0", value = 70 }); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g1", value = 60 }); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g2", value = 100 }); data.Add(new ChartDataRecord { date = 1370563260000, graph = "g0", value = 71 }); data.Add(new ChartDataRecord { date = 1370563260000, graph = "g2", value = 110 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g0", value = 72 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g1", value = 62 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g2", value = 150 }); 

我正在使用的图表框架(amCharts)要求JSON数据提供程序的格式如下:

 { "data": [ { "date": 1370563200000, "g0": 70, "g1": 60, "g2": 100 }, { "date": 1370563260000, "g0": 71, "g2": 110 }, { "date": 1370563320000, "g0": 72, "g1": 62, "g2": 150 } ], ...other chart properties } 

将样本List序列化为此JSON结构的推荐方法是什么? Json.NET框架中是否有一些可以使这相当容易的东西? 如果没有,这将如何手动完成? 我是否应该为List使用更动态的数据结构并尝试使用我的LINQ-to-Entities查询填充它?

您可以使用自定义转换器执行此操作,如下所示:

 class ChartDataRecordCollectionConverter : JsonConverter { ///  /// Writes the JSON representation of the object. ///  /// The  to write to.The value.The calling serializer. public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var set = (ChartDataRecordCollection) value; writer.WriteStartObject(); writer.WritePropertyName("data"); writer.WriteStartArray(); //Group up the records in the collection by the 'date' property foreach (var record in set.GroupBy(x => x.date)) { writer.WriteStartObject(); writer.WritePropertyName("date"); writer.WriteValue(record.Key); //Write the graph/value pairs as properties and values foreach (var part in record) { writer.WritePropertyName(part.graph); writer.WriteValue(part.value); } writer.WriteEndObject(); } writer.WriteEndArray(); writer.WriteEndObject(); } ///  /// Reads the JSON representation of the object. ///  /// The  to read from.Type of the object.The existing value of object being read.The calling serializer. ///  /// The object value. ///  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var result = new ChartDataRecordCollection(); var obj = JObject.Load(reader); var container = obj["data"]; //Examine each object in the array of values from the result foreach (JObject item in container) { //Get and store the date property var date = item["date"].Value(); //For each property that is not the date property on the object, construct a // ChartDataRecord with the appropriate graph/value pair foreach (var property in item.Properties()) { if (property.Name == "date") { continue; } result.Add(new ChartDataRecord { date = date, graph = property.Name, value = item[property.Name].Value() }); } } return result; } ///  /// Determines whether this instance can convert the specified object type. ///  /// Type of the object. ///  /// true if this instance can convert the specified object type; otherwise, false. ///  public override bool CanConvert(Type objectType) { return objectType == typeof (ChartDataRecordCollection); } } 

此转换器将对包含List的集合类型进行操作,如此定义

 [JsonConverter(typeof(ChartDataRecordCollectionConverter))] public class ChartDataRecordCollection : List { public ChartDataRecordCollection() { } public ChartDataRecordCollection(IEnumerable records) { AddRange(records); } } 

用法示例(和正确性certificate):

 public class ChartDataRecord { public long date { get; set; } public string graph { get; set; } public int value { get; set; } public override bool Equals(object obj) { var o = (ChartDataRecord) obj; return o.date == date && o.graph == graph && o.value == value; } } ... static void Main(string[] args) { var data = new List { new ChartDataRecord { date = 1370563200000, graph = "g0", value = 70 }, new ChartDataRecord { date = 1370563200000, graph = "g1", value = 60 }, new ChartDataRecord { date = 1370563200000, graph = "g2", value = 100 }, new ChartDataRecord { date = 1370563260000, graph = "g0", value = 71 }, new ChartDataRecord { date = 1370563260000, graph = "g2", value = 110 }, new ChartDataRecord { date = 1370563320000, graph = "g0", value = 72 }, new ChartDataRecord { date = 1370563320000, graph = "g1", value = 62 }, new ChartDataRecord { date = 1370563320000, graph = "g2", value = 150 } }; var records = new ChartDataRecordCollection(data); var result = JsonConvert.SerializeObject(records); Console.WriteLine(result); var test = JsonConvert.DeserializeObject(result); Console.WriteLine(records.SequenceEqual(test)); Console.ReadLine(); } 

输出:

 {"data":[{"date":1370563200000,"g0":70,"g1":60,"g2":100},{"date":1370563260000,"g0":71,"g2":110},{"date":1370563320000,"g0":72,"g1":62,"g2":150}]} true 

是的,JSON.NET可以很容易地处理它。 只需将列表添加到另一个对象的“data”属性中,然后对其进行序列化。 下面的示例对“包装器”对象使用匿名类型,但“正常”CLR类型也可以正常工作。

 public class StackOverflow_17012831 { public class ChartDataRecord { public long date { get; set; } public string graph { get; set; } public int value { get; set; } } public static void Test() { List data = new List(); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g0", value = 70 }); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g1", value = 60 }); data.Add(new ChartDataRecord { date = 1370563200000, graph = "g2", value = 100 }); data.Add(new ChartDataRecord { date = 1370563260000, graph = "g0", value = 71 }); data.Add(new ChartDataRecord { date = 1370563260000, graph = "g2", value = 110 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g0", value = 72 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g1", value = 62 }); data.Add(new ChartDataRecord { date = 1370563320000, graph = "g2", value = 150 }); var obj = new { data = data, name = "Name" }; string str = JsonConvert.SerializeObject(obj); Console.WriteLine(str); } }