如何使用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具有NameId等属性。 这是结果:

 ... "dictionaryProp": [ [ { "name": "MyCustomTypeInstance1.Name", "description": null, "id": null }, 3 ], [ { "name": "MyCustomTypeInstance2.Name", "description": null, "id": null }, 2 ] ] ...