反序列化JSON数组数组

时间:2016-07-18 10:37:08

标签: c# json.net

我有以下JSON数据,我希望将其反序列化为C#POCO对象,但我无法对数组数组进行反序列化。

var json = @"{
  ""name"": ""Foo"",
  ""pages"": [
    {
         ""page"": 1,
          ""fields"": [
            {
                  ""name"": ""stuffs"",
                  ""rows"": [
                    [{ ""value"" : ""$199""}, { ""value"": ""foo"" }],
                    [{ ""value"" : ""$222""}, { ""value"": ""bar"", ""color"": ""blue"" }]
                  ]
        }]
    }
  ]
}";

例外是

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'UserQuery+TableRow' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
    To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
    Path 'rows[0]', line 4, position 5.

根据异常消息的建议,我确实尝试了所有这些事情,但只是面临更多错误。

这些是我的POCO对象

public class Document
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("pages")]
    public Page[] Pages { get; set; }
}

public class Page
{
    [JsonProperty("page")]
    public int PageNumber { get; set; }

    [JsonProperty("fields")]
    public FieldBase[] FieldsBase { get; set; }
}

public class TableRow
{
    public Cell[] Cells { get; set; }
}

public class Cell
{
    [JsonProperty("value")]
    public string Value { get; set; }

    [JsonProperty("color")]
    public string Color { get; set; }
}

public abstract class FieldBase
{
    [JsonProperty("name")]
    public string Name { get; set; }
}
public class Table : FieldBase
{
    [JsonProperty("rows")]
    public TableRow[] Rows { get; set; } = new TableRow[0];
}

我的现场转换器处理抽象类(不确定这是否重要)

public class FieldConverter : JsonConverter
{
    static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() { ContractResolver = new BaseSpecifiedConcreteClassConverter() };

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(FieldBase));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        return JsonConvert.DeserializeObject<Table>(jo.ToString(), SpecifiedSubclassConversion);
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException(); // won't be called because CanWrite returns false
    }
}

public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
{
    protected override JsonConverter ResolveContractConverter(Type objectType)
    {
        if (typeof(FieldBase).IsAssignableFrom(objectType) && !objectType.IsAbstract)
            return null; // pretend TableSortRuleConvert is not specified (thus avoiding a stack overflow)
        return base.ResolveContractConverter(objectType);
    }
}

以下代码行在LINQPad中执行时产生错误

JsonConvert.DeserializeObject<Document>(json, new FieldConverter()).Dump();

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

在你的json中,"rows"是一个锯齿状的数组:

"rows": [[{ "value" : "$199"}, { "value": "foo" }]]

但是,在对象模型中,这对应于包含单元格数组的TableRow类数组。因此,您需要另一个JsonConverter将每个TableRow序列化为单元格数组而不是对象:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var cells = serializer.Deserialize<Cell[]>(reader);
        return new TableRow { Cells = cells };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var row = (TableRow)value;
        serializer.Serialize(writer, row.Cells);
    }
}

public class JsonDerivedTypeConverter<TBase, TDerived> : JsonConverter where TDerived : TBase
{
    public JsonDerivedTypeConverter()
    {
        if (typeof(TBase) == typeof(TDerived))
            throw new InvalidOperationException("TBase and TDerived cannot be identical");
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(TBase);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return serializer.Deserialize<TDerived>(reader);
    }

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

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

然后,要反序列化,请执行:

var settings = new JsonSerializerSettings
{
    Converters = new JsonConverter[] { new TableRowConverter(), new JsonDerivedTypeConverter<FieldBase, Table>() },
};

var doc = JsonConvert.DeserializeObject<Document>(json, settings);

示例fiddle