Json.netを使用したJSONオブジェクト配列の逆シリアル化


118

返されたjsonに次のサンプル構造を使用するAPIを使用しようとしています

[
   {
      "customer":{
         "first_name":"Test",
         "last_name":"Account",
         "email":"test1@example.com",
         "organization":"",
         "reference":null,
         "id":3545134,
         "created_at":"2013-08-06T15:51:15-04:00",
         "updated_at":"2013-08-06T15:51:15-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      }
   },
   {
      "customer":{
         "first_name":"Test",
         "last_name":"Account2",
         "email":"test2@example.com",
         "organization":"",
         "reference":null,
         "id":3570462,
         "created_at":"2013-08-12T11:54:58-04:00",
         "updated_at":"2013-08-12T11:54:58-04:00",
         "address":"",
         "address_2":"",
         "city":"",
         "state":"",
         "zip":"",
         "country":"",
         "phone":""
      }
   }
]

JSON.netは次のような構造でうまく機能します

{
    "customer": {
        ["field1" : "value", etc...],
        ["field1" : "value", etc...],
    }
}

しかし、提供された構造でそれを満足させる方法を理解することはできません。

デフォルトのJsonConvert.DeserializeObject(content)を使用すると、正しい顧客数が得られますが、すべてのデータはnullです。

CustomerList(下記)を実行すると、「現在のJSON配列を逆シリアル化できません」という例外が発生します。

public class CustomerList
{
    public List<Customer> customer { get; set; }
}

考え?


これはあなたの質問に答えますか?C#を使用してJSONを
デシリアライズする

回答:


187

Jsonをデシリアライズする新しいモデルを作成できますCustomerJson

public class CustomerJson
{
    [JsonProperty("customer")]
    public Customer Customer { get; set; }
}

public class Customer
{
    [JsonProperty("first_name")]
    public string Firstname { get; set; }

    [JsonProperty("last_name")]
    public string Lastname { get; set; }

    ...
}

そして、あなたは簡単にjsonを逆シリアル化することができます:

JsonConvert.DeserializeObject<List<CustomerJson>>(json);

それが役に立てば幸い !

ドキュメンテーション:JSONのシリアライズとデシリアライズ


1
ありがとう。問題を考えすぎていた。あなたが最初に答えたので、あなたの答えは受け入れられました。
Shawn C.

2
JsonConvert.DeserializeObject <List <CustomerJson >>(json); 文字列入力に最適です。
Markel Mairs 2017年

DeserializeObject()ARMを実行しているAndroidフォンでは遅い。その場合のより良い解決策はありますか?
Tadej

1
JObjectでナビゲートしてみてくださいJObject.Parse(json);
Joffrey Kern

47

モデルを作成したくない場合は、次のコードを使用します。

var result = JsonConvert.DeserializeObject<
  List<Dictionary<string, 
    Dictionary<string, string>>>>(content);

注:これは動作しませんあなたの JSON文字列。これは、JSON構造の一般的な解決策ではありません


10
これはひどい解決策です。代わりに、モデルを作成したくない場合は、var result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);
a11smiles

1
@ a11smilesなぜそれがひどい解決策なのか説明してください。
タイラーロング

2
まず、さまざまなタイプのIEnumerable実装に対する不必要なメモリ割り当て(List <Tuple>と比較して3)。次に、ソリューションは2つの異なるキーを意味します-各辞書に1つ。複数の顧客が同じ名を持つ場合はどうなりますか?キーに違いはありません。ソリューションでは、この競合を考慮していません。
a11smiles

2
@ a11smiles各顧客は個別の辞書です。したがって、同じ名前の顧客が複数いる場合でも問題はありません。
タイラーロング

1
@ a11smilesなぜうまくいくと思いましたかvar result = JsonConvert.DeserializeObject<Tuple<string, string, string>>(content);。どうやらそれは動作しません
タイラーロング

1

受け入れられた回答を使用するには、を使用して各レコードにアクセスCustomers[i].customerする必要があり、追加のCustomerJsonクラスが必要です。これは少し面倒です。そうしたくない場合は、以下を使用できます。

public class CustomerList
{
    [JsonConverter(typeof(MyListConverter))]
    public List<Customer> customer { get; set; }
}

List<>配列ではなくを使用していることに注意してください。次のクラスを作成します。

class MyListConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Values())
        {
            var childToken = child.Children().First();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(childToken.CreateReader(), newObject);
            list.Add(newObject);
        }
        return list;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

1

上記の内容を少し変更しました。検証した私のJsonフォーマットは

{
    mycollection:{[
           {   
               property0:value,
               property1:value,
             },
             {   
               property0:value,
               property1:value,
             }
           ]

         }
       }

AlexDevの応答を使用して、私はこれを行い、各子をループさせ、そこからリーダーを作成しました

 public partial class myModel
{
    public static List<myModel> FromJson(string json) => JsonConvert.DeserializeObject<myModelList>(json, Converter.Settings).model;
}

 public class myModelList {
    [JsonConverter(typeof(myModelConverter))]
    public List<myModel> model { get; set; }

}

class myModelConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        var list = Activator.CreateInstance(objectType) as System.Collections.IList;
        var itemType = objectType.GenericTypeArguments[0];
        foreach (var child in token.Children())  //mod here
        {
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(child.CreateReader(), newObject); //mod here
            list.Add(newObject);
        }
        return list;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();

}

0

JC_VAからのさらなる変更、彼が持っているものを取り、MyModelConverterを...に置き換えます。

public class MyModelConverter : JsonConverter
{
    //objectType is the type as specified for List<myModel> (i.e. myModel)
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader); //json from myModelList > model
        var list = Activator.CreateInstance(objectType) as System.Collections.IList; // new list to return
        var itemType = objectType.GenericTypeArguments[0]; // type of the list (myModel)
        if (token.Type.ToString() == "Object") //Object
        {
            var child = token.Children();
            var newObject = Activator.CreateInstance(itemType);
            serializer.Populate(token.CreateReader(), newObject);
            list.Add(newObject);
        }
        else //Array
        {
            foreach (var child in token.Children())
            {
                var newObject = Activator.CreateInstance(itemType);
                serializer.Populate(child.CreateReader(), newObject);
                list.Add(newObject);
            }
        }
        return list;

    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsGenericType && (objectType.GetGenericTypeDefinition() == typeof(List<>));
    }
    public override bool CanWrite => false;
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
}

これは次のいずれかのjsonで機能するはずです

myModelList{
 model: [{ ... object ... }]
}

または

myModelList{
 model: { ... object ... }
}

彼らは両方のように解析されることになります

myModelList{
 model: [{ ... object ... }]
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.