首页 文章

Newtonsoft.Json,Populate Dictionary失败

提问于
浏览
3

我通过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);

但是会发生以下异常:

无法将字符串'$ type'转换为字典键类型'System.Guid' . 创建TypeConverter以将字符串转换为键类型对象 . 路径'$ type',第2行,位置10.在Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader阅读器,对象目标)在Newtonsoft.Json.Jop.Serialulate.Populate(JsonReader阅读器,对象目标)的Newtonsoft.Json.JsonSerializer.Populate(JsonReader阅读器,对象目标)Newtonsoft.Json.JsonConvert.PopulateObject(字符串值,对象目标, JsonSerializerSettings设置)

我像这样写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);
    }
}

EDIT:

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

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??

1 回答

  • 4

    The problem 是您在序列化字典时指定了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”:“测试”
    }

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

    The solution 是在 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开始,使用此设置的内存使用和速度会略有降低 .

    Alternatively ,如果您没有无条件地在JSON中需要元数据类型信息,则可以使用_2922723序列化并仅发出多态类型的类型信息,而 Dictionary<Guid, string> 则不是 .

    Relatedly ,使用 TypeNameHandling 时,请注意Newtonsoft docs中的这一注意事项:

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

    有关可能需要的原因的讨论,请参阅TypeNameHandling caution in Newtonsoft Json .

相关问题