C# 如何使用Json.Net对带有自定义键的字典进行序列化/反序列化?
我有以下类,我将其用作字典中的键:C# 如何使用Json.Net对带有自定义键的字典进行序列化/反序列化?,c#,.net,json,json.net,C#,.net,Json,Json.net,我有以下类,我将其用作字典中的键: public class MyClass { private readonly string _property; public MyClass(string property) { _property = property; } public string Property { get { ret
public class MyClass
{
private readonly string _property;
public MyClass(string property)
{
_property = property;
}
public string Property
{
get { return _property; }
}
public override bool Equals(object obj)
{
MyClass other = obj as MyClass;
if (other == null) return false;
return _property == other._property;
}
public override int GetHashCode()
{
return _property.GetHashCode();
}
}
我正在运行的测试如下:
[Test]
public void SerializeDictionaryWithCustomKeys()
{
IDictionary<MyClass, object> expected = new Dictionary<MyClass, object>();
expected.Add(new MyClass("sth"), 5.2);
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string output = JsonConvert.SerializeObject(expected, Formatting.Indented, jsonSerializerSettings);
var actual = JsonConvert.DeserializeObject<IDictionary<MyClass, object>>(output, jsonSerializerSettings);
CollectionAssert.AreEqual(expected, actual);
}
这显然是错误的。我怎样才能让它工作?这应该可以做到: 序列化:
JsonConvert.SerializeObject(expected.ToArray(), Formatting.Indented, jsonSerializerSettings);
JsonConvert.DeserializeObject<KeyValuePair<IDataKey, object>[]>(output, jsonSerializerSettings).ToDictionary(kv => kv.Key, kv => kv.Value);
通过调用expected.ToArray()
可以序列化KeyValuePair
对象数组,而不是字典
反序列化:
JsonConvert.SerializeObject(expected.ToArray(), Formatting.Indented, jsonSerializerSettings);
JsonConvert.DeserializeObject<KeyValuePair<IDataKey, object>[]>(output, jsonSerializerSettings).ToDictionary(kv => kv.Key, kv => kv.Value);
JsonConvert.DeserializeObject(输出,jsonSerializerSettings).ToDictionary(kv=>kv.Key,kv=>kv.Value);
在这里,您反序列化数组,然后使用.ToDictionary(…)
调用检索字典
我不确定输出是否满足您的期望,但肯定它通过了平等断言。Grx70的答案很好-只是在这里添加了一个替代解决方案。我在一个WebAPI项目中遇到了这个问题,我没有调用
SerializeObject
,而是允许序列化自动进行
这个基于的自定义JsonConverter
为我实现了以下技巧:
public class DeepDictionaryConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (typeof(IDictionary).IsAssignableFrom(objectType) ||
TypeImplementsGenericInterface(objectType, typeof(IDictionary<,>)));
}
private static bool TypeImplementsGenericInterface(Type concreteType, Type interfaceType)
{
return concreteType.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Type type = value.GetType();
IEnumerable keys = (IEnumerable)type.GetProperty("Keys").GetValue(value, null);
IEnumerable values = (IEnumerable)type.GetProperty("Values").GetValue(value, null);
IEnumerator valueEnumerator = values.GetEnumerator();
writer.WriteStartArray();
foreach (object key in keys)
{
valueEnumerator.MoveNext();
writer.WriteStartArray();
serializer.Serialize(writer, key);
serializer.Serialize(writer, valueEnumerator.Current);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
更简单、完整的解决方案,使用自定义JsonConverter
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
public class CustomDictionaryConverter<TKey, TValue> : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(Dictionary<TKey, TValue>);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> serializer.Serialize(writer, ((Dictionary<TKey, TValue>)value).ToList());
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
=> serializer.Deserialize<KeyValuePair<TKey, TValue>[]>(reader).ToDictionary(kv => kv.Key, kv => kv.Value);
}
使用Newtonsoft.Json;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
公共类CustomDictionaryConverter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)=>objectType==typeof(字典);
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
=>serializer.Serialize(writer,((字典)值).ToList());
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
=>serializer.Deserialize(reader.ToDictionary)(kv=>kv.Key,kv=>kv.Value);
}
用法:
[JsonConverter(typeof(CustomDictionaryConverter<KeyType, ValueType>))]
public Dictionary<KeyType, ValueType> MyDictionary;
[JsonConverter(typeof(CustomDictionaryConverter))]
公共词典;
JSON并不总能很好地处理字典,为什么不重写MyClass
的.ToString()
?为什么这么复杂的字典键?为什么不在类中包含dictionary值,然后用列表替换dictionary?您可以指定预期的输出应该是什么样子吗?因为我很确定复杂的属性名不是JSON的一部分…@TMcKeown,在实际代码中有不同类型的键。我可以实现ToString()
和相应的类型转换器,但我希望序列化程序能为我完成这项工作…@mason,显然不是。这个解决方案非常好。您也可以通过提供ReadJson方法的实现来完成这项工作吗?谢谢但是如何反序列化它呢。我也希望看到反序列化。这里有一个要点,有反序列化:太好了,谢谢。注意--value
在WriteJson
中可以为null,所以我添加了一个小检查--if(value==null)序列化程序;else serializer.Serialize(writer,((字典)值).ToList())