2016-07-18 2 views
1

У меня есть следующие данные JSON, которые я хотел бы десериализовать на объект C# POCO, но у меня возникли проблемы с десериализацией массива массивов.Deserialize массив массивов JSON

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(); 

Любая помощь была бы принята с благодарностью.

+0

см. Https://dotnetfiddle.net/ZLZvpt –

+0

Благодарим за попытку, но она не использует объекты, требуемые по вопросу. –

+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.

+0

Спасибо. Я понимаю библиотеку намного лучше, и мой код короче! –

Смежные вопросы