2016-07-18 42 views
1

次のJSONデータをC#POCOオブジェクトに逆シリアル化したいのですが、配列の配列を逆シリアル化するのに問題があります。配列の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(); 

ご協力いただければ幸いです。あなたのJSONで

+0

https://dotnetfiddle.net/ZLZvpt –

+0

試していただきありがとうございますが、質問で必要なオブジェクトは使用していません。 –

+0

あなたのクラス構造が間違っていると思います –

答えて

1

"rows"はジャグ配列です:

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

しかし、あなたのオブジェクトモデルで、これはセルのアレイを含んで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(); 
    } 
} 

:したがって、あなたは、セルの配列ではなくオブジェクトとして各TableRowをシリアル化するために、別のJsonConverterが必要になります

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

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

fiddle

+0

ありがとうございます。私は図書館が今よりずっと良くなり、コードが短くなっていることを理解しています! –

関連する問題