使用Newtonsoft将JSON数组数组反序列化为List of Tuples
我从在线服务提供商处收到的数据如下:
{ name: "test data", data: [ [ "2017-05-31", 2388.33 ], [ "2017-04-30", 2358.84 ], [ "2017-03-31", 2366.82 ], [ "2017-02-28", 2329.91 ] ], }
我想将它解析成一个看起来像这样的对象:
public class TestData { public string Name; public List<Tuple> Data; }
我唯一能找到的是如何将一组对象解析成一个tulples列表,例如: Json.NET反序列化其他类型中的Tuple 不起作用?
有没有办法编写一个可以处理这个问题的自定义转换器?
所以使用JSON.NET LINQ,我设法按照你的规定让它工作……
var result = JsonConvert.DeserializeObject(json); var data = new TestData { Name = (string)result["name"], Data = result["data"] .Select(t => new Tuple(DateTime.Parse((string)t[0]), (double)t[1])) .ToList() };
这是我写的完整测试
public class TestData { public string Name; public List> Data; } [TestMethod] public void TestMethod1() { var json = @"{ name: ""test data"", data: [ [ ""2017-05-31"", 2388.33 ], [ ""2017-04-30"", 2358.84 ], [ ""2017-03-31"", 2366.82 ], [ ""2017-02-28"", 2329.91 ] ], }"; var result = JsonConvert.DeserializeObject(json); var data = new TestData { Name = (string)result["name"], Data = result["data"] .Select(t => new Tuple(DateTime.Parse((string)t[0]), (double)t[1])) .ToList() }; Assert.AreEqual(2388.33, data.Data[0].Item2); }
然而,虽然这可能有用,但我同意其余的评论/答案,使用元组可能不是正确的方法。 从长远来看,使用具体的POCO肯定会更加难以维护,因为Tuple<,>
的Item1
和Item2
属性。
它们不是最具描述性的……
我从这里采用了通用的TupleConverter: 在另一种类型中的Tuple <...>的Json.NET反序列化不起作用? 并制作了一个通用的TupleListConverter。
用法:
public class TestData { public string Name; [Newtonsoft.Json.JsonConverter(typeof(TupleListConverter))] public List> Data; } public void Test(string json) { var testData = JsonConvert.DeserializeObject(json); foreach (var tuple in testData.data) { var dateTime = tuple.Item1; var price = tuple.Item2; ... do something... } }
转换器:
public class TupleListConverter : Newtonsoft.Json.JsonConverter { public override bool CanConvert(Type objectType) { return typeof(Tuple) == objectType; } public override object ReadJson( Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { if (reader.TokenType == Newtonsoft.Json.JsonToken.Null) return null; var jArray = Newtonsoft.Json.Linq.JArray.Load(reader); var target = new List>(); foreach (var childJArray in jArray.Children()) { var tuple = new Tuple( childJArray[0].ToObject(), childJArray[1].ToObject() ); target.Add(tuple); } return target; } public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { serializer.Serialize(writer, value); } }
如果有人对ValueTuples的更通用的解决方案感兴趣
public class TupleConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var type = value.GetType(); var array = new List
用法如下:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new TupleConverter()); var list = new List<(DateTime, double)> { (DateTime.Now, 7.5) }; var json = JsonConvert.SerializeObject(list, settings); var result = JsonConvert.DeserializeObject(json, list.GetType(), settings);
我会创建一个特定于任务的类,而不是使用元组。 在这种情况下,您的JSON数据作为字符串列表的列表进入,这有点难以处理。 一种方法是反序列化为List
,然后转换。 例如,我会使用这样的3个类: >
public class IntermediateTestData { public string Name; public List> Data; } public class TestData { public string Name; public IEnumerable Data; } public class TestDataItem { public DateTime Date { get; set; } public double Value { get; set; } }
现在反序列化如下:
var intermediate = JsonConvert.DeserializeObject(json); var testData = new TestData { Name = intermediate.Name, Data = intermediate.Data.Select(d => new TestDataItem { Date = DateTime.Parse(d[0]), Value = double.Parse(d[1]) }) };