Json.Netを使用してNameValueCollectionのカスタムサブクラスをシリアル化する

user481779

次のクラスがあり、Jsonへのシリアル化に失敗しました。

class HL7 : NameValueCollection
{
  public List<HL7> Children { get; set; }
  public HL7()
  {
    Children = new List<HL7>();
  }
}

私はそのようにオブジェクトを作成し、それにデータを追加しました:

HL7 hl7 = new HL7();
hl7.Add("a", "123");
hl7.Add("b", "456");
hl7.Children.Add(new HL7());
hl7.Children[0].Add("c", "123");
hl7.Children[0].Add("d", "456");

私が電話するとき

JsonConvert.SerializeObject(hl7)

私は受け取ります

["a","b"]

私は次のことを期待していました:

{
  "a": "123",
  "b": "456",
  "Children": [
    {
      "c": "123",
      "d": "456",
    }
  ]
} 
dbc

ここで起こっていることがいくつかあります:

  1. Json.NETは、キーを反復処理するNameValueCollectionためにNameValueCollection実装されているため、カスタムコンバーターなしでをシリアル化することはできませんIEnumerableIDictionary、キーと値を反復処理するために実装されていませんこれがJson.NETで問題を引き起こす理由の詳細については、この回答参照してください

  2. NameValueCollection実装しているためIEnumerable、Json.NETはクラスをコレクションと見なし、名前付きプロパティを持つJSONオブジェクトではなく、JSON配列としてシリアル化します。したがって、Childrenはシリアル化されません。繰り返しますが、これを修正するにはカスタムコンバーターが必要になります。

  3. 上記の問題が解決されたと仮定すると、のHL7サブクラスにNameValueCollection名前の付いたキーがある"Children"場合、シリアル化時に無効なJSON、つまりプロパティ名が重複したオブジェクトが生成さます。明確なシリアル化を目的として、名前と値をネストされたプロパティ(「Values」などの名前)に移動することをお勧めします。

  4. NameValueCollection 実際には、特定のキー文字列に対して複数の文字列値を持つことができるため、そのエントリ値は単一の文字列ではなくJSON配列としてシリアル化する必要があります。

これらすべてをまとめると、次のコードになります。

[JsonConverter(typeof(HL7Converter))]
public class HL7 : NameValueCollection
{
    public List<HL7> Children { get; set; }
    public HL7()
    {
        Children = new List<HL7>();
    }
}

public class HL7Converter : JsonConverter
{
    class HL7Proxy
    {
        public NameValueCollectionDictionaryWrapper Values { get; set; }
        public List<HL7> Children { get; set; }
    }


    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(HL7);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var proxy = serializer.Deserialize<HL7Proxy>(reader);
        if (proxy == null)
            return existingValue;
        var hl7 = existingValue as HL7;
        if (hl7 == null)
            hl7 = new HL7();
        hl7.Add(proxy.Values.GetCollection());
        if (proxy.Children != null)
            hl7.Children.AddRange(proxy.Children);
        return hl7;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        HL7 hl7 = (HL7)value;
        if (hl7 == null)
            return;

        serializer.Serialize(writer, new HL7Proxy { Children = hl7.Children, Values = new NameValueCollectionDictionaryWrapper(hl7) });
    }
}

// Proxy dictionary to serialize & deserialize a NameValueCollection.  We use a proxy dictionary rather than a real dictionary because NameValueCollection is an ordered collection but the generic dictionary class is unordered.
public class NameValueCollectionDictionaryWrapper: IDictionary<string, string []>
{
    readonly NameValueCollection collection;

    public NameValueCollectionDictionaryWrapper()
        : this(new NameValueCollection())
    {
    }

    public NameValueCollectionDictionaryWrapper(NameValueCollection collection)
    {
        this.collection = collection;
    }

    // Method instead of a property to guarantee that nobody tries to serialize it.
    public NameValueCollection GetCollection()
    {
        return collection;
    }

    #region IDictionary<string,string[]> Members

    public void Add(string key, string[] value)
    {
        if (collection.GetValues(key) != null)
            throw new ArgumentException("Duplicate key " + key);
        foreach (var str in value)
            collection.Add(key, str);
    }

    public bool ContainsKey(string key)
    {
        return collection.GetValues(key) != null;
    }

    public ICollection<string> Keys
    {
        get {
            return collection.AllKeys;
        }
    }

    public bool Remove(string key)
    {
        bool found = ContainsKey(key);
        if (found)
            collection.Remove(key);
        return found;
    }

    public bool TryGetValue(string key, out string[] value)
    {
        value = collection.GetValues(key);
        return value != null;
    }

    public ICollection<string[]> Values
    {
        get {
            return Enumerable.Range(0, collection.Count).Select(i => collection.GetValues(i)).ToArray();
        }
    }

    public string[] this[string key]
    {
        get
        {
            var value = collection.GetValues(key);
            if (value == null)
                throw new KeyNotFoundException();
            return value;
        }
        set
        {
            Remove(key);
            Add(key, value);
        }
    }

    #endregion

    #region ICollection<KeyValuePair<string,string[]>> Members

    public void Add(KeyValuePair<string, string[]> item)
    {
        Add(item.Key, item.Value);
    }

    public void Clear()
    {
        collection.Clear();
    }

    public bool Contains(KeyValuePair<string, string[]> item)
    {
        string [] value;
        if (!TryGetValue(item.Key, out value))
            return false;
        return EqualityComparer<string[]>.Default.Equals(item.Value, value); // Consistent with Dictionary<TKey, TValue>
    }

    public void CopyTo(KeyValuePair<string, string[]>[] array, int arrayIndex)
    {
        foreach (var item in this)
            array[arrayIndex++] = item;
    }

    public int Count
    {
        get { return collection.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(KeyValuePair<string, string[]> item)
    {
        if (Contains(item))
            return Remove(item.Key);
        return false;
    }

    #endregion

    #region IEnumerable<KeyValuePair<string,string[]>> Members

    public IEnumerator<KeyValuePair<string, string[]>> GetEnumerator()
    {
        foreach (string key in collection)
        {
            yield return new KeyValuePair<string, string[]>(key, collection.GetValues(key)); 
        }
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

次のテストケースを使用します。

        HL7 hl7 = new HL7();
        hl7.Add("a", "123");
        hl7.Add("b", "456");
        hl7.Add("Children", "Children");
        hl7.Children.Add(new HL7());
        hl7.Children[0].Add("c", "123");
        hl7.Children[0].Add("d", "456");
        hl7.Children[0].Add("d", "789");

        var json = JsonConvert.SerializeObject(hl7, Formatting.Indented);

        Debug.WriteLine(json);

次のJSONを提供します。

{
  "Values": {
    "a": [
      "123"
    ],
    "b": [
      "456"
    ],
    "Children": [
      "Children"
    ]
  },
  "Children": [
    {
      "Values": {
        "c": [
          "123"
        ],
        "d": [
          "456",
          "789"
        ]
      },
      "Children": []
    }
  ]
}

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

json.netを使用してオブジェクトにカスタムデシリアライズする方法

分類Dev

Pythonのカスタムフィールドを使用してオブジェクトをjsonにシリアル化する方法

分類Dev

Gsonを使用してカスタムクラスのArrayListをJSONにシリアル化し、HTTP経由でデータを送信します

分類Dev

JSON.NETでカスタムJsonConverterを実装して、基本クラスオブジェクトのリストを逆シリアル化するにはどうすればよいですか?

分類Dev

SpringBoot-カスタムオブジェクトの配列を使用してカスタムオブジェクトをJSONシリアル化

分類Dev

JSON.NETを使用して派生クラスに逆シリアル化する

分類Dev

複数のプロパティによるサブタイプを使用してJSONをクラスに逆シリアル化する方法は?

分類Dev

Json.NETでのシリアル化中にすべてのクラスにカスタムタイプ名を追加する

分類Dev

Json.NETを使用してオブジェクトのリストをシリアル化する

分類Dev

jsonオブジェクト内のカスタムオブジェクトをシリアル化します

分類Dev

参照にカスタム形式を使用している場合、Json.NETを使用して参照によってオブジェクトを逆シリアル化するにはどうすればよいですか?

分類Dev

Newtonsoft.Jsonライブラリを使用して文字列をC#を使用してカスタムオブジェクトに逆シリアル化する方法

分類Dev

Jacksonを使用してカスタムメソッドからJSONに出力をシリアル化する方法は?

分類Dev

Jackson ObjectMapperを使用して、サブクラス名をスーパークラスではなくJSONにシリアル化する

分類Dev

アクティブなモデルシリアライザーを使用してjson-apiシリアル化モデルのIDをカスタマイズするにはどうすればよいですか?

分類Dev

Json.NETを使用したカスタム逆シリアル化

分類Dev

ジャクソンを使用してjsonを逆シリアル化し、サブクラスタイプを修正します

分類Dev

Objective-Cを使用してJSONをカスタムオブジェクトに逆シリアル化します

分類Dev

タイムスタンプを使用してPlayFrameworkでケースクラスをJsonにシリアル化する

分類Dev

Json.Netを使用してこのカスタム構造体を逆シリアル化できないのはなぜですか?

分類Dev

Json.NETを使用してオブジェクトをJavaScriptコンストラクター呼び出しにシリアル化できますか?

分類Dev

JSON Jackson-カスタムシリアライザーでポリモーフィッククラスをシリアル化するときの例外

分類Dev

JsonConverterを使用したJson.NETカスタムシリアル化-「デフォルト」の動作を取得する方法

分類Dev

サブオブジェクトのc#json.netカスタムシリアル化

分類Dev

インターフェイスのコレクションを逆シリアル化すると、カスタムコンバーターを使用した以前のデータモデルからのJSONの逆シリアル化が失敗します

分類Dev

JSON.NETを使用してjsonを逆シリアル化しますが、特定のクラスの元のjsonを追加フィールドに保持します

分類Dev

json4sを使用してオプションの値クラスインスタンスをシリアル化する際の問題

分類Dev

JsonConverterを使用したC#でのカスタムJSON逆シリアル化

分類Dev

サブタイプを使用してjsonをオブジェクトに逆シリアル化する方法は?

Related 関連記事

  1. 1

    json.netを使用してオブジェクトにカスタムデシリアライズする方法

  2. 2

    Pythonのカスタムフィールドを使用してオブジェクトをjsonにシリアル化する方法

  3. 3

    Gsonを使用してカスタムクラスのArrayListをJSONにシリアル化し、HTTP経由でデータを送信します

  4. 4

    JSON.NETでカスタムJsonConverterを実装して、基本クラスオブジェクトのリストを逆シリアル化するにはどうすればよいですか?

  5. 5

    SpringBoot-カスタムオブジェクトの配列を使用してカスタムオブジェクトをJSONシリアル化

  6. 6

    JSON.NETを使用して派生クラスに逆シリアル化する

  7. 7

    複数のプロパティによるサブタイプを使用してJSONをクラスに逆シリアル化する方法は?

  8. 8

    Json.NETでのシリアル化中にすべてのクラスにカスタムタイプ名を追加する

  9. 9

    Json.NETを使用してオブジェクトのリストをシリアル化する

  10. 10

    jsonオブジェクト内のカスタムオブジェクトをシリアル化します

  11. 11

    参照にカスタム形式を使用している場合、Json.NETを使用して参照によってオブジェクトを逆シリアル化するにはどうすればよいですか?

  12. 12

    Newtonsoft.Jsonライブラリを使用して文字列をC#を使用してカスタムオブジェクトに逆シリアル化する方法

  13. 13

    Jacksonを使用してカスタムメソッドからJSONに出力をシリアル化する方法は?

  14. 14

    Jackson ObjectMapperを使用して、サブクラス名をスーパークラスではなくJSONにシリアル化する

  15. 15

    アクティブなモデルシリアライザーを使用してjson-apiシリアル化モデルのIDをカスタマイズするにはどうすればよいですか?

  16. 16

    Json.NETを使用したカスタム逆シリアル化

  17. 17

    ジャクソンを使用してjsonを逆シリアル化し、サブクラスタイプを修正します

  18. 18

    Objective-Cを使用してJSONをカスタムオブジェクトに逆シリアル化します

  19. 19

    タイムスタンプを使用してPlayFrameworkでケースクラスをJsonにシリアル化する

  20. 20

    Json.Netを使用してこのカスタム構造体を逆シリアル化できないのはなぜですか?

  21. 21

    Json.NETを使用してオブジェクトをJavaScriptコンストラクター呼び出しにシリアル化できますか?

  22. 22

    JSON Jackson-カスタムシリアライザーでポリモーフィッククラスをシリアル化するときの例外

  23. 23

    JsonConverterを使用したJson.NETカスタムシリアル化-「デフォルト」の動作を取得する方法

  24. 24

    サブオブジェクトのc#json.netカスタムシリアル化

  25. 25

    インターフェイスのコレクションを逆シリアル化すると、カスタムコンバーターを使用した以前のデータモデルからのJSONの逆シリアル化が失敗します

  26. 26

    JSON.NETを使用してjsonを逆シリアル化しますが、特定のクラスの元のjsonを追加フィールドに保持します

  27. 27

    json4sを使用してオプションの値クラスインスタンスをシリアル化する際の問題

  28. 28

    JsonConverterを使用したC#でのカスタムJSON逆シリアル化

  29. 29

    サブタイプを使用してjsonをオブジェクトに逆シリアル化する方法は?

ホットタグ

アーカイブ