Newtonsoft.Json,填充字典失败 [英] Newtonsoft.Json, Populate Dictionary failed
问题描述
var serializeSettings = new JsonSerializerSettings
我将序列化一个字典到json by Newtonsoft.json {
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:测试
}
我尝试通过此代码将json反序列化为字典:
var newDic = new Dictionay< Guid,string>();
var deserializeSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
Formatting = Formatting.Indented
}
JsonConvert.PopulateObject(serializedObject,newDic,deserializeSettings);
但是发生这种异常:
无法将字符串'$ type'转换为字典键类型'System.Guid'。创建一个TypeConverter以将其从字符串转换为键类型对象。路径'$ type',行2,位置10。
在Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary,JsonReader reader,JsonDictionaryContract contract,JsonProperty containerProperty,在Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader,Object target)中
在Newtonsoft.Json.JsonSerializer.PopulateInternal(JsonReader reader,Object target)
在Newtonsoft.Json.JsonSerializer.Populate(JsonReader reader,Object target)
$ Newtonsoft.Json.JsonConvert.PopulateObject(String value,Object target,JsonSerializerSettings设置)中的
$ b
我写这样的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<&的Guid GT;(读取器);
}
catch
{
return Guid.Empty;
}
}
public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer)
{
serializer.Serialize(writer,value);
}
}
编辑: p>
我发现我的问题。将代码更改为序列化json到Dictionary<字符串,字符串>现在生成的字典中的第一个项目是:
Kay:$ 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
为什么?
问题是指定< a href =http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_JsonSerializer_TypeNameHandling.htm =nofollow> TypeNameHandling = TypeNameHandling.All
当序列化你的字典。这将导致元数据$ type
属性作为字典中的第一个对象发布:
{
$ type:System.Collections.Generic.Dictionary`2 [[System.Guid,mscorlib,Version = 2.0.0.0,Culture =中性,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
,当构造相应的c#对象时,该令牌通常由Json.NET使用。但是您正在使用 PopulateObject
在预先分配的字典上。因此,元数据属性在构建期间不会消耗,而Json.NET会尝试将其添加到字典中,并失败。
解决方案设置 MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
在 deserializeSettings
。这样做会导致$ 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
序列化,并且只会发布多态类型的类型信息,您的 Dictionary< Guid,string>
不是。
I serialize a dictionary to json by Newtonsoft.json and bellow code :
var serializeSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
Formatting = Formatting.Indented
};
var serializedObject = JsonConvert.SerializeObject(dic, serializeSettings);
this code generate a json like this :
{
"$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"
}
I try to deserialize json to dictionary by this code :
var newDic = new Dictionay<Guid,string>();
var deserializeSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
Formatting = Formatting.Indented
}
JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings);
But this exception occurs :
Could not convert string '$type' to dictionary key type 'System.Guid'. Create a TypeConverter to convert from the string to the key type object. Path '$type', line 2, position 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)
I write GuidConverter like this and use it. but not work
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<Guid>(reader);
}
catch
{
return Guid.Empty;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
EDIT:
I found my problem. Change code to deserialize json to Dictionary< string, string > and now First item in generated dictionary is :
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"
Why??
The problem is that you have specified TypeNameHandling = TypeNameHandling.All
when serializing your dictionary. This causes a metadata "$type"
property to be emitted as the first object in the dictionary:
{ "$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" }
When deserializing using DeserializeObject
, this token is normally consumed by Json.NET when the corresponding c# object is constructed. But you are using PopulateObject
on a pre-allocated dictionary. Thus the metadata property is not consumed during construction and instead Json.NET tries to add it to the dictionary, and fails.
The solution is to set MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
in deserializeSettings
. Doing so will cause the "$type"
property to be consumed or ignored (as appropriate) unconditionally:
var deserializeSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
Formatting = Formatting.Indented,
MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead
};
JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings);
Please note that, from the release notes, there is a slight cost in memory usage and speed from using this setting.
Alternatively, if you don't unconditionally need metadata type information in your JSON, you could serialize with TypeNameHandling = TypeNameHandling.Auto
and only emit type information for polymorphic types, which your Dictionary<Guid, string>
is not.
这篇关于Newtonsoft.Json,填充字典失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!