Newtonsoft.Json,Populate Dictionary失败

我通过Newtonsoft.json将字典序列化为json,并且代码如下:

var serializeSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, Formatting = Formatting.Indented }; var serializedObject = JsonConvert.SerializeObject(dic, serializeSettings); 

这段代码生成一个像这样的json:

 { "$type": "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "9648af76-7986-4b34-8b2c-97b2345769ef": "Test" } 

我尝试通过以下代码将json反序列化为字典:

 var newDic = new Dictionay(); var deserializeSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, Formatting = Formatting.Indented } JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings); 

但是会发生以下exception:

无法将字符串’$ type’转换为字典键类型’System.Guid’。 创建TypeConverter以将字符串转换为键类型对象。 路径’$ type’,第2行,第10位。

at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary,JsonReader reader,JsonDictionaryContract contract,JsonProperty containerProperty,String id)

at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader,Object target)

at Newtonsoft.Json.JsonSerializer.PopulateInternal(JsonReader reader,Object target)

at Newtonsoft.Json.JsonSerializer.Populate(JsonReader reader,Object target)

at Newtonsoft.Json.JsonConvert.PopulateObject(String value,Object target,JsonSerializerSettings settings)

我像这样写GuidConverter并使用它。 但不行

 public class GuidConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType.IsAssignableFrom(typeof(Guid)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { try { return serializer.Deserialize(reader); } catch { return Guid.Empty; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } 

编辑:

我发现了我的问题。 更改代码以将json反序列化为Dictionary ,现在生成的字典中的第一项是:

 Kay: "$type" Value : "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 

为什么??

问题是您在序列化字典时指定了TypeNameHandling = TypeNameHandling.All 。 这会导致元数据"$type"属性作为字典中的第一个对象发出:

 { "$type": "System.Collections.Generic.Dictionary`2[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "9648af76-7986-4b34-8b2c-97b2345769ef": "Test" } 

使用DeserializeObject反序列DeserializeObject ,当构造相应的c#对象时,此标记通常由Json.NET使用。 但是您在预先分配的字典上使用PopulateObject 。 因此,在构造期间不会消耗元数据属性,而是Json.NET尝试将其添加到字典中,并且失败。

解决方案是在deserializeSettings设置MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead 。 这样做会导致无条件地使用或忽略(视情况而定) "$type"属性:

 var deserializeSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, TypeNameAssemblyFormat = FormatterAssemblyStyle.Full, Formatting = Formatting.Indented, MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead }; JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings); 

请注意,从发行说明中 ,使用此设置的内存使用和速度会略有降低

或者 ,如果您无法在JSON中无条件地需要元数据类型信息,则可以使用TypeNameHandling = TypeNameHandling.Auto序列化,并仅发出TypeNameHandling = TypeNameHandling.Auto类型的类型信息,而Dictionary则不会。

相关地 ,在使用TypeNameHandling ,请注意Newtonsoft文档中的这一注意事项:

当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。 使用非None以外的值进行反序列化时,应使用自定义SerializationBindervalidation传入类型。

有关可能需要这样做的讨论,请参阅Newtonsoft Json中的TypeNameHandling警告