我通过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<Guid,string>();
var deserializeSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
Formatting = Formatting.Indented
}
JsonConvert.PopulateObject(serializedObject, newDic, deserializeSettings);
但是会发生这种异常:
无法转换字符串&#39; $ type&#39;字典键类型&#39; System.Guid&#39;。创建TypeConverter以将字符串转换为键类型对象。路径&#39; $ type&#39;,第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<Guid>(reader);
}
catch
{
return Guid.Empty;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
修改
我发现了我的问题。更改代码以将json反序列化为Dictionary&lt; string,string&gt;现在生成的字典中的第一项是:
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"
为什么?
答案 0 :(得分:4)
问题是您在序列化词典时指定了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
进行反序列化时,当构造相应的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);
请注意,使用此设置时,release notes,的内存使用量和速度会有轻微的成本。
或者,如果您无法在JSON中无条件地需要元数据类型信息,则可以使用TypeNameHandling = TypeNameHandling.Auto
进行序列化,并仅发出多态类型的类型信息,您的{{{ 1}}不是。
相关,在使用Dictionary<Guid, string>
时,请注意Newtonsoft docs中的这一注意事项:
当您的应用程序从外部源反序列化JSON时,应谨慎使用TypeNameHandling。使用非None以外的值进行反序列化时,应使用自定义SerializationBinder验证传入类型。
有关可能需要执行此操作的讨论,请参阅 TypeNameHandling caution in Newtonsoft Json 。