web-dev-qa-db-ja.com

オブジェクト配列をJSONにシリアル化する

私は辞書のラッパーであるタイプを持っています-基本的にキー/値ストア。このタイプのオブジェクトの配列をJSONにシリアル化したいと思います。私はJSONとJson.NET(newtonsoft.json)にかなり慣れていません。

私のタイプには、次のように辞書をjsonにシリアル化するToJsonというメソッドがあります。

public string ToJson()
{
  return JsonConvert.SerializeObject(this.values);
}    

そして、これらのオブジェクトの配列をシリアル化しようとします

var json = JsonConvert.SerializeObject(objectArray)

もちろん、配列内の各オブジェクトがシリアル化されており、各オブジェクトの「ToJson」メソッドにシリアル化プロセスを指示する方法がわからないため、これは機能しません。

辞書オブジェクトの配列を渡せば、希望どおりに機能させることができます。

多分私はいくつかのシリアル化属性が欠けていますか?

編集:

さらにいくつかのドキュメントを読んだ後、(JsonConverterアプローチを検討する前に)より短い方法を試しました-「JsonPropertyAttribute」を使用します。プライベート辞書のメンバーにそれを適用することは、私が望まないメンバー名もシリアル化することを除いて、ほとんど仕事をしました。 JsonPropertyAttributeを使用して、メンバー名ではなくメンバー値をシリアル化する方法はありますか?

8
alwayslearning

内部ディクショナリがJSONにラッパーが存在しないかのように表示されるようにラッパークラスをシリアル化するには、カスタムJsonConverterが必要です。 JsonConverterを使用すると、特定のクラスで何をシリアル化および/または逆シリアル化するかを直接制御できます。

以下は、あなたのケースで機能するはずのコンバーターです。ディクショナリを保持するためのvaluesというフィールドがあることを除いて、ラッパークラスに関する詳細を実際に提供しなかったため、リフレクションを使用してアクセスしました。クラスにディクショナリを直接操作するパブリックメソッドがある場合は、必要に応じて、代わりにそれらのメソッドを使用するようにコンバータを変更できます。コードは次のとおりです。

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        MyWrapper wrapper = (MyWrapper)value;
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        JObject jo = JObject.FromObject(field.GetValue(wrapper));
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        MyWrapper wrapper = new MyWrapper();
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(wrapper, jo.ToObject(field.FieldType));
        return wrapper;
    }
}

カスタムコンバーターをラッパークラスに関連付けるには、クラス定義に[JsonConverter]属性を追加します。

[JsonConverter(typeof(DictionaryWrapperConverter))]
class MyWrapper : IEnumerable
{
    Dictionary<string, string> values = new Dictionary<string, string>();

    public void Add(string key, string value)
    {
        values.Add(key, value);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return values.GetEnumerator();
    }
}

これは、コンバーターの動作を示す完全なデモです。最初にラッパークラスの単一インスタンスをシリアル化および逆シリアル化し、次にラッパーのリストをシリアル化および逆シリアル化します。

class Program
{
    static void Main(string[] args)
    {
        MyWrapper wrapper = new MyWrapper();
        wrapper.Add("foo", "bar");
        wrapper.Add("fizz", "bang");

        // serialize single wrapper instance
        string json = JsonConvert.SerializeObject(wrapper, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize single wrapper instance
        wrapper = JsonConvert.DeserializeObject<MyWrapper>(json);

        foreach (KeyValuePair<string, string> kvp in wrapper)
        {
            Console.WriteLine(kvp.Key + "=" + kvp.Value);
        }
        Console.WriteLine();
        Console.WriteLine("----------\n");

        MyWrapper wrapper2 = new MyWrapper();
        wrapper2.Add("a", "1");
        wrapper2.Add("b", "2");
        wrapper2.Add("c", "3");

        List<MyWrapper> list = new List<MyWrapper> { wrapper, wrapper2 };

        // serialize list of wrappers
        json = JsonConvert.SerializeObject(list, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize list of wrappers
        list = JsonConvert.DeserializeObject<List<MyWrapper>>(json);

        foreach (MyWrapper w in list)
        {
            foreach (KeyValuePair<string, string> kvp in w)
            {
                Console.WriteLine(kvp.Key + "=" + kvp.Value);
            }
            Console.WriteLine();
        }
    }
}

出力:

{
  "foo": "bar",
  "fizz": "bang"
}

foo=bar
fizz=bang

----------

[
  {
    "foo": "bar",
    "fizz": "bang"
  },
  {
    "a": "1",
    "b": "2",
    "c": "3"
  }
]

foo=bar
fizz=bang

a=1
b=2
c=3
7
Brian Rogers