Grz*_*nio 7 .net c# json 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();
}
}
Run Code Online (Sandbox Code Playgroud)
我正在运行的测试在这里:
[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);
}
Run Code Online (Sandbox Code Playgroud)
测试失败,因为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
}
Run Code Online (Sandbox Code Playgroud)
这显然是错的.我怎样才能让它发挥作用?
Grx*_*x70 11
这应该做的伎俩:
连载:
JsonConvert.SerializeObject(expected.ToArray(), Formatting.Indented, jsonSerializerSettings);
Run Code Online (Sandbox Code Playgroud)
通过调用expected.ToArray()你序列化一个KeyValuePair<MyClass, object>对象数组而不是字典.
反序列化:
JsonConvert.DeserializeObject<KeyValuePair<IDataKey, object>[]>(output, jsonSerializerSettings).ToDictionary(kv => kv.Key, kv => kv.Value);
Run Code Online (Sandbox Code Playgroud)
在这里反序列化数组,然后通过.ToDictionary(...)调用检索字典.
我不确定输出是否符合您的期望,但肯定会通过相等的断言.
Grx70的答案很好 - 只需在这里添加替代解决方案.我在一个Web API项目中遇到了这个问题,我没有调用它,SerializeObject但允许序列化自动发生.
JsonConverter基于Brian Rogers对类似问题的回答的这个习惯对我有用:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
在我的例子中,我Dictionary<MyCustomType, int>在一个MyCustomType具有类似Name和的属性的类上序列化一个属性Id.这是结果:
...
"dictionaryProp": [
[
{
"name": "MyCustomTypeInstance1.Name",
"description": null,
"id": null
},
3
],
[
{
"name": "MyCustomTypeInstance2.Name",
"description": null,
"id": null
},
2
]
]
...
Run Code Online (Sandbox Code Playgroud)
使用自定义 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);
}
Run Code Online (Sandbox Code Playgroud)
用法:
[JsonConverter(typeof(CustomDictionaryConverter<KeyType, ValueType>))]
public Dictionary<KeyType, ValueType> MyDictionary;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10981 次 |
| 最近记录: |