C#: キー・値の順番を保持してJSONをデシリアライズ

はじめに

  • キー・値形式のJSONを解析する場合、JsonSerializer.Deserialize<Dictionary<T, V>>()を使って簡単に実現できますが、キー・値の順番は保証されません。
    ここでは、このキー・値の順番を保証する方法を紹介します。
  • 次の環境を使用して動作確認しています。
    OSWindows 10(64ビット)
    IDEMicrosoft Visual Studio Community 2019(16.8.5) + C#(8.0)
  • 完全なソースコードはこちらで公開しています。
  • なお、System.Text.Jsonでサポートされているコレクション型はこちらのリファレンスをご覧ください。

前提データ・クラス

サンプルで使用するJSONデータ、JSONデータを格納するクラスです。

  • キー・値形式になっているJSONを使用します。
    本来であれば、JsonSerializer.Deserialize<Dictionary<string, MyEntity>>()で解析できます。
  • 次のクラスにJSONデータ(キー・値形式)の値を格納する想定です。

OrderedDictionaryを使用する方法

  • 順番を保持できるDictionaryであるOrderedDictionary(System.Collections.Specialized)を使用できます。
  • このクラスはジェネリックに対応していないため、値の解析処理を自身で実装する必要があります。
  • OrderedDictionaryの列挙子としてDictionaryEntry型が返却されるので、そこからキーと値を取得できます。
  • 値はJsonElement型として返却されるので、そこから数値や文字列を取得できます。詳細はこちらをご覧ください。
  • 次の例では、JsonElementオブジェクトから個別に値を取得してMyEntityクラスに格納します。
  • 次の例では、JsonElementオブジェクトから取得したJSONを再度デシリアライズしてMyEntityクラスに値を格納します。

JsonDocumentを使用する方法

上記の例では、Dictionaryの延長の位置づけでOrderedDictionaryを使う方法を紹介しました。
ジェネリックに対応しておらず、結局JsonElementを使って手動で解析する必要があります。
これだったら、素直にJsonDocumentを使って解析した方がいいかとも思います。

参考)JsonElementの使い方

  • Jsonデータの解析結果は、(内部的に)JsonElementで再帰的に表現されています。
  • JsonElementは、値またはオブジェクト(入れ子になったデータ)を表現しています。
    • 値の例:「”value1″: 111」というJSONの値「111」
    • オブジェクトの例:「”key1″: { “value1”: 123, “value2”: “test1”,…}」というJSONの値「{ “value1”: 123, “value2”: “test1”,…}」
  • 何を表現しているかはValueKind(JsonValueKind列挙型)で判定できます。
  • 数値、文字列、真偽等の値を表現している場合、その値をGetInt32(), GetString()等で整数型や文字列として取得できます。値が配列形式の場合、EnumerateArray()で列挙子を取得できるので、ループ処理で配列値の取得や変換を行えます。
  • オブジェクトを表現している場合、オブジェクトに含まれるキー・値(「”value1″: 111」等)はプロパティ(JsonProperty型)として保持されています。JsonPropertyのName, Valueがキー・値に対応しています。
  • プロパティの一覧を取得する場合はEnumerateObject()を使用します。プロパティの値を直接取得する場合は、GetProperty(string)を使用します。
  • JsonElementが表現する値やオブジェクトのJSONはGetRawText()で取得できます。