Json.Net cannot serialize property of a class derived from dictionary

前端 未结 1 1421
花落未央
花落未央 2021-01-06 02:34

I have a class that is derived from Dictionary. Also the class itself has a ClientId property. I want to de-serialize the collection of this class into JSON str

相关标签:
1条回答
  • 2021-01-06 03:31

    Yes, you are correct, you will need to do some sort of custom serialization. Json.NET will either serialize the key/value pairs of the dictionary as a JSON object (using JsonDictionaryContract), or the properties of the dictionary as a JSON object (using JsonObjectContract) if you mark the type with [JsonObject] - but not both. I suspect doing both was not implemented to thereby avoid the possibility of run-time name clashes when the dictionary contains a key with the same name as a property, e.g.:

    var client3 = new ClientSettings();
    client3.ClientId = "Client1";
    client3["ClientId"] = "Conflicting Value";
    

    According to the IETF standard,

    When the names within an object are not unique, the behavior of software that receives such an object is unpredictable.

    Thus this is a situation best avoided.

    One possible implementation is as follows:

    [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
    public class ClientSettings : Dictionary<string, string>, IClientSettings
    {
        [JsonProperty]
        public string ClientId { get; set; }
    
        [JsonProperty]
        IDictionary<string, string> Items { get { return new DictionaryWrapper<string, string>(this); } }
    }
    

    Using

    public class DictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
    {
        readonly IDictionary<TKey, TValue> dictionary;
    
        public DictionaryWrapper(IDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            this.dictionary = dictionary;
        }
    
        #region IDictionary<TKey,TValue> Members
    
        public void Add(TKey key, TValue value) { dictionary.Add(key, value); }
    
        public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); }
    
        public ICollection<TKey> Keys { get { return dictionary.Keys; } }
    
        public bool Remove(TKey key) { return dictionary.Remove(key); }
    
        public bool TryGetValue(TKey key, out TValue value) { return dictionary.TryGetValue(key, out value); }
    
        public ICollection<TValue> Values { get { return dictionary.Values; } }
    
        public TValue this[TKey key]
        {
            get { return dictionary[key]; }
            set { dictionary[key] = value; }
        }
    
        #endregion
    
        #region ICollection<KeyValuePair<TKey,TValue>> Members
    
        public void Add(KeyValuePair<TKey, TValue> item) { dictionary.Add(item); }
    
        public void Clear() { dictionary.Clear(); }
    
        public bool Contains(KeyValuePair<TKey, TValue> item) { return dictionary.Contains(item); }
    
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { dictionary.CopyTo(array, arrayIndex); }
    
        public int Count { get { return dictionary.Count; } }
    
        public bool IsReadOnly { get { return dictionary.IsReadOnly; } }
    
        public bool Remove(KeyValuePair<TKey, TValue> item) { return dictionary.Remove(item); }
    
        #endregion
    
        #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return dictionary.GetEnumerator(); }
    
        #endregion
    
        #region IEnumerable Members
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); }
    
        #endregion
    }
    

    MemberSerialization.OptIn is used to prevent base class properties such as Count, Comparer, Keys and Values from being serialized.

    With this, your JSON will look like:

    [
      {
        "ClientId": "Client2",
        "Items": {
          "key1": "value1",
          "key2": "value2",
          "key3": "value3"
        }
      }
    ]
    
    0 讨论(0)
提交回复
热议问题