我有一个序列化到DataContractJsonSerializer的字典,我想与Newtonsoft.Json反序列化。
DataContractJsonSerializer已将Dictionary序列化为键/值对的列表:
{"Dict":[{"Key":"Key1","Value":"Val1"},{"Key":"Key2","Value":"Val2"}]}
我可以提供任何很酷的选择JsonConvert.DeserializeObject<>(),使其同时支持该数据格式和Newtonsoft.Json的格式吗?
JsonConvert.DeserializeObject<>()
{"Dict":{"Key1":"Val1","Key2":"Val2"}}
是Newtonsoft.Json创建的漂亮格式,我希望能够在过渡期内读取旧的DataContract格式和新的Newtonsoft格式。
简化示例:
//[JsonArray] public sealed class Data { public IDictionary<string, string> Dict { get; set; } } [TestMethod] public void TestSerializeDataContractDeserializeNewtonsoftDictionary() { var d = new Data { Dict = new Dictionary<string, string> { {"Key1", "Val1"}, {"Key2", "Val2"}, } }; var oldJson = String.Empty; var formatter = new DataContractJsonSerializer(typeof (Data)); using (var stream = new MemoryStream()) { formatter.WriteObject(stream, d); oldJson = Encoding.UTF8.GetString(stream.ToArray()); } var newJson = JsonConvert.SerializeObject(d); // [JsonArray] on Data class gives: // // System.InvalidCastException: Unable to cast object of type 'Data' to type 'System.Collections.IEnumerable'. Console.WriteLine(oldJson); // This is tha data I have in storage and want to deserialize with Newtonsoft.Json, an array of key/value pairs // {"Dict":[{"Key":"Key1","Value":"Val1"},{"Key":"Key2","Value":"Val2"}]} Console.WriteLine(newJson); // This is what Newtonsoft.Json generates and should also be supported: // {"Dict":{"Key1":"Val1","Key2":"Val2"}} var d2 = JsonConvert.DeserializeObject<Data>(newJson); Assert.AreEqual("Val1", d2.Dict["Key1"]); Assert.AreEqual("Val2", d2.Dict["Key2"]); var d3 = JsonConvert.DeserializeObject<Data>(oldJson); // Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into // type 'System.Collections.Generic.IDictionary`2[System.String,System.String]' because the type requires a JSON // object (e.g. {"name":"value"}) to deserialize correctly. // // To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type // to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be // deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from // a JSON array. // // Path 'Dict', line 1, position 9. Assert.AreEqual("Val1", d3.Dict["Key1"]); Assert.AreEqual("Val2", d3.Dict["Key2"]); }
您可以为此使用自定义转换器,具体取决于字典以什么令牌开头,将其反序列化为JSON.NET的默认方式,或将其反序列化为数组,然后将该数组转换为Dictionary:
Dictionary
public class DictionaryConverter : JsonConverter { public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { IDictionary<string, string> result; if (reader.TokenType == JsonToken.StartArray) { JArray legacyArray = (JArray)JArray.ReadFrom(reader); result = legacyArray.ToDictionary( el => el["Key"].ToString(), el => el["Value"].ToString()); } else { result = (IDictionary<string, string>) serializer.Deserialize(reader, typeof(IDictionary<string, string>)); } return result; } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, string>).IsAssignableFrom(objectType); } public override bool CanWrite { get { return false; } } }
然后,您可以使用Dict属性装饰Data类中的JsonConverter属性:
Dict
Data
JsonConverter
public sealed class Data { [JsonConverter(typeof(DictionaryConverter))] public IDictionary<string, string> Dict { get; set; } }
然后对两个字符串进行反序列化应能按预期工作。