如何使用Json.Net使用自定义键序列化/反序列化字典?
我有以下类,我用作字典中的键:
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 expected = new Dictionary(); 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>(output, jsonSerializerSettings); CollectionAssert.AreEqual(expected, actual); }
测试失败,因为Json.Net似乎在字典键上使用ToString()
方法,而不是正确地序列化它们。 上面测试得到的json是:
{ "$type": "System.Collections.Generic.Dictionary`2[[RiskAnalytics.UnitTests.API.TestMarketContainerSerialisation+MyClass, RiskAnalytics.UnitTests],[System.Object, mscorlib]], mscorlib", "RiskAnalytics.UnitTests.API.TestMarketContainerSerialisation+MyClass": 5.2 }
这显然是错的。 我怎样才能让它发挥作用?
这应该是诀窍:
连载:
JsonConvert.SerializeObject(expected.ToArray(), Formatting.Indented, jsonSerializerSettings);
通过调用expected.ToArray()
您将序列化KeyValuePair
对象的数组,而不是字典。
反序列化:
JsonConvert.DeserializeObject[]>(output, jsonSerializerSettings).ToDictionary(kv => kv.Key, kv => kv.Value);
在这里反序列化数组,然后使用.ToDictionary(...)
调用检索字典。
我不确定输出是否符合您的期望,但肯定会通过相等的断言。
Grx70的答案很好 – 只需在这里添加替代解决方案。 我在一个Web API项目中遇到了这个问题,我没有调用SerializeObject
但允许序列化自动发生。
基于Brian Rogers对类似问题的回答的这个自定义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(); } }
在我的例子中,我在一个类上序列化了一个Dictionary
属性,其中MyCustomType
具有Name
和Id
等属性。 这是结果:
... "dictionaryProp": [ [ { "name": "MyCustomTypeInstance1.Name", "description": null, "id": null }, 3 ], [ { "name": "MyCustomTypeInstance2.Name", "description": null, "id": null }, 2 ] ] ...