使用Newtonsoft将JSON数组数组反序列化为List of Tuples

Bri*_*ice 7 c# arrays json tuples deserialization

我从在线服务提供商处收到的数据如下:

{
  name: "test data",
  data: [
    [ "2017-05-31", 2388.33 ],
    [ "2017-04-30", 2358.84 ],
    [ "2017-03-31", 2366.82 ],
    [ "2017-02-28", 2329.91 ]
  ],
}       
Run Code Online (Sandbox Code Playgroud)

我想将它解析成一个看起来像这样的对象:

public class TestData
{
   public string Name;
   public List<Tuple<DateTime, double>> Data;
}
Run Code Online (Sandbox Code Playgroud)

我唯一能找到的是如何将一组对象解析成一个tulples列表,例如:Json.NET反序列化其他类型中的Tuple <...>不起作用?

有没有办法编写一个可以处理这个问题的自定义转换器?

fal*_*ing 5

如果有人对 ValueTuples 的更通用解决方案感兴趣

public class TupleConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var type = value.GetType();
        var array = new List<object>();
        FieldInfo fieldInfo;
        var i = 1;

        while ((fieldInfo = type.GetField($"Item{i++}")) != null)
            array.Add(fieldInfo.GetValue(value));

        serializer.Serialize(writer, array);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var argTypes = objectType.GetGenericArguments();
        var array = serializer.Deserialize<JArray>(reader);
        var items = array.Select((a, index) => a.ToObject(argTypes[index])).ToArray();

        var constructor = objectType.GetConstructor(argTypes);
        return constructor.Invoke(items);
    }

    public override bool CanConvert(Type type)
    {
        return type.Name.StartsWith("ValueTuple`");
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

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);
Run Code Online (Sandbox Code Playgroud)


Bri*_*ice 1

我从这里获取了通用 TupleConverter:Json.NET deserialization of Tuple<...> inside another type does not work? 并制作了一个通用的 TupleListConverter。

用法:

public class TestData
{
    public string Name;
    [Newtonsoft.Json.JsonConverter(typeof(TupleListConverter<DateTime, double>))]
    public List<Tuple<DateTime, double>> Data;
}

public void Test(string json)
{
    var testData = JsonConvert.DeserializeObject<TestData>(json);
    foreach (var tuple in testData.data)
    {
        var dateTime = tuple.Item1;
        var price = tuple.Item2;
        ... do something...
    }
}
Run Code Online (Sandbox Code Playgroud)

转换器:

public class TupleListConverter<U, V> : Newtonsoft.Json.JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(Tuple<U, V>) == 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<Tuple<U, V>>();

        foreach (var childJArray in jArray.Children<Newtonsoft.Json.Linq.JArray>())
        {
            var tuple = new Tuple<U, V>(
                childJArray[0].ToObject<U>(),
                childJArray[1].ToObject<V>()
            );
            target.Add(tuple);
        }

        return target;
    }

    public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}
Run Code Online (Sandbox Code Playgroud)