2014-07-10 93 views
5

我有下面的類,我在一本字典的主要用途:如何使用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<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

JSON並不總是很好地處理字典,你爲什麼不重寫'MyClass'的'.ToString()'? –

+0

爲什麼這麼複雜的字典鍵?爲什麼不在你的類裏面有字典值,然後用列表替換字典? – gunr2171

+0

你能指定預期輸出應該是什麼樣子嗎?因爲我非常肯定,複雜的屬性名稱不是JSON的一部分...... – Grx70

回答

7

這應該做的伎倆:

連載:

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(...)通話。

我不確定輸出結果是否符合您的期望,但肯定會通過等式斷言。

4

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(); 
    } 
} 

以我爲例,我是在課堂,MyCustomType沒有像NameId性能序列化Dictionary<MyCustomType, int>屬性。這是結果:

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

這個解決方案非常棒。您是否也可以通過爲ReadJson方法提供實現來完成此操作?謝謝! – Nikhil