我有以下类,我用作词典中的键:
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);
}
测试失败,因为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
}
这显然是错误的。我怎样才能让它发挥作用?
答案 0 :(得分:11)
这应该可以解决问题:
序列化:
JsonConvert.SerializeObject(expected.ToArray(), Formatting.Indented, jsonSerializerSettings);
通过调用expected.ToArray()
,您将序列化KeyValuePair<MyClass, object>
个对象而不是字典。
反序列化:
JsonConvert.DeserializeObject<KeyValuePair<IDataKey, object>[]>(output, jsonSerializerSettings).ToDictionary(kv => kv.Key, kv => kv.Value);
在这里,您反序列化数组,然后使用.ToDictionary(...)
调用检索字典。
我不确定输出是否符合您的期望,但肯定会通过相等的断言。
答案 1 :(得分:6)
Grx70的答案很好 - 只需在此处添加替代解决方案。我在Web API项目中遇到了这个问题,我没有调用SerializeObject
但是允许序列化自动发生。
这个基于Brian Rogers' answer to a similar question的自定义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, int>
具有MyCustomType
和Name
等属性的类上序列化Id
属性。这是结果:
...
"dictionaryProp": [
[
{
"name": "MyCustomTypeInstance1.Name",
"description": null,
"id": null
},
3
],
[
{
"name": "MyCustomTypeInstance2.Name",
"description": null,
"id": null
},
2
]
]
...
答案 2 :(得分:0)
使用自定义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);
}
用法:
[JsonConverter(typeof(CustomDictionaryConverter<KeyType, ValueType>))]
public Dictionary<KeyType, ValueType> MyDictionary;