Json.Net无法序列化从字典派生的类的属性 [英] Json.Net cannot serialize property of a class derived from dictionary
问题描述
我有一个从Dictionary派生的类.该类本身也具有ClientId
属性.我想使用Json.Net
将此类的集合反序列化为JSON字符串,因此遵循文档
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 string using Json.Net
So followed the documentation here
public interface IClientSettings: IDictionary<string, string>
{
string ClientId { get; set; }
}
public class ClientSettings : Dictionary<string, string>, IClientSettings
{
public string ClientId { get; set; }
}
然后我将列表反序列化为字符串
and then I am de-serializing list into string
var list = new List<IClientSettings>();
var client1 = new ClientSettings();
client1.ClientId = "Client1";
client1.Add("key1", "value1");
client1.Add("key2", "value2");
client1.Add("key3", "value3");
var client2 = new ClientSettings();
client1.ClientId = "Client2";
client2.Add("key1", "value1");
client2.Add("key2", "value2");
client2.Add("key3", "value3");
list.Add(client1);
list.Add(client2);
string json = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine(json);
但是,这不会序列化Clientid
属性.下面是输出.
However this does not serialize Clientid
property. Below is the output.
[
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
]
I am not sure what I am missing here. I have also found suggestion here that suggest to do custom serialization, is that the only option I have?
推荐答案
是的,您是正确的,您将需要进行一些自定义序列化. Json.NET将序列化字典的键/值对作为JSON对象(使用 JsonDictionaryContract
),或将字典的属性作为JSON对象使用(使用
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";
根据 IETF标准,
当对象中的名称不是唯一的时,接收到该对象的软件的行为是不可预测的.
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); } }
}
使用
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
用于防止序列化诸如Count
,Comparer
,Keys
和Values
的基类属性.
MemberSerialization.OptIn
is used to prevent base class properties such as Count
, Comparer
, Keys
and Values
from being serialized.
这样,您的JSON将如下所示:
With this, your JSON will look like:
[
{
"ClientId": "Client2",
"Items": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
]
这篇关于Json.Net无法序列化从字典派生的类的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!