无法反序列化异构 json 数据

Failed to desirialize heterogeneous json data

所以我正在使用 Json.net 反序列化 json REST API 返回给服务器的数据,它 returns 的数据结构是:

{ "keyXXX" : [[1,2,3,...]...], "last": 12345 }

问题是 "key" 也是数据的一部分,它不是名为 "key" 的字段,所以我不能使用 class/struct,我不得不使用 IDictionary<string, int[][]> 对于第一部分,但是 "last" 部分将抛出异常,因为它是单个整数而不是数组的数组。 这是我试过的:

var dec = JsonConvert.DeserializeObject<IDictionary<string, int[][]>>(data);

这会引发 json 异常:

Newtonsoft.Json.JsonSerializationException: Error converting value 1501555920 to type 'System.Decimal[][]'. Path 'last'.

//define a class
public class DPInfo
{
    public decimal[][] points { get; set; }
    public long last { get; set; }
}
var dec = JsonConvert.DeserializeObject<DPInfo>(data);

这将不起作用,因为数组的字段名称是动态的,因此 points 之后将不包含任何内容。

有什么办法可以解决这个问题?

您可以使用 JObject.Parse 将字符串解析为 dynamic 变量。它至少会确保从字符串到 JSON 的转换成功,但是您需要在访问每个 属性 之前验证每个 属性 中是否有一个值。

在您的情况下,声明将如下所示:

dynamic data = JObject.Parse("{ 'keyXXX' : [[1,2,3,...]...], 'last': 12345 }");

您需要自定义 JsonConverter 来解决这个问题。这是一个应该有效的方法:

public class DPInfoConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DPInfo);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        JProperty points = obj.Properties().FirstOrDefault(p => p.Name != "last");

        DPInfo info = new DPInfo
        {
            key = points.Name,   // remove this line if you don't need the key
            points = points.Value.ToObject<decimal[][]>(),
            last = (long)obj["last"]
        };

        return info;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用它,只需将 [JsonConverter] 属性添加到您的 class:

[JsonConverter(typeof(DPInfoConverter))]
public class DPInfo
{
    public string key { get; set; }   // remove this line if you don't need the key
    public decimal[][] points { get; set; }
    public long last { get; set; }
}

然后,像往常一样反序列化,它应该可以工作:

string json = @"
{
  ""keyXXX"": [[1, 2, 3]],
  ""last"": 12345
}";

DPInfo info = JsonConvert.DeserializeObject<DPInfo>(json);

Fiddle: https://dotnetfiddle.net/7S6STp