简体   繁体   English

Json.NET无法序列化集合字典

[英]Json.NET fails to serialize dictionary of sets

I'm trying to serialize (and later on deserialize) a Dictionary<string, ISet<string>> . 我正在尝试序列化(稍后反序列化) Dictionary<string, ISet<string>> Unfortunately, Json.NET (v6.0.3 via NuGet) fails to do this. 不幸的是,Json.NET(通过NuGet的v6.0.3)无法做到这一点。 What I do is 我要做的是

var value = new Dictionary<string, ISet<string>>
    {
        {"foo", new HashSet<string>{"bar"}}
    };
var settings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Objects,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
    };
var json = JsonConvert.SerializeObject(value, settings);

The variable json then holds the string 变量json然后保存字符串

{"$type":"System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.ISet`1[[System.String, mscorlib]], System]], mscorlib","foo":["bar"]}

Now I want to deserialize the string with 现在我想用反序列化字符串

JsonConvert.DeserializeObject<IDictionary<string, ISet<string>>>(json, settings);

which fails in resolving the Dictionary type, because it cannot find the System assembly that ISet belongs to. 由于无法找到ISet所属的System程序集,因此无法解析Dictionary类型。 When I instead do the following 当我改为执行以下操作时

JsonConvert.DeserializeObject<IDictionary<string, ISet<string>>>(json);

everything works just fine. 一切正常。 So it appears that the TypeNameHandling setting (changing/omitting the format does not change anything) actually breaks deserialization. 因此,看来TypeNameHandling设置(更改/省略格式不会更改任何内容)实际上破坏了反序列化。

I found that, if I don't set the TypeNameHandling settings, the serialized $type properties are simply ignored. 我发现,如果不设置TypeNameHandling设置,则序列化的$type属性将被忽略。 Ie, when deserializing, the type information is taken solely from the target type where they are resolved. 即,在反序列化时,类型信息仅取自解析它们的目标类型。 This works. 这可行。

When setting the TypeNameHandling , type resolution happens via reflection within the Json.NET assembly, which does not have a dependency on the System assembly and therefore fails to resolve the ISet interface. 设置TypeNameHandling ,类型解析是通过Json.NET程序集内的反射发生的,该程序集不依赖于System程序集,因此无法解析ISet接口。 I can fix this by registering on AppDomain.CurrentDomain.AssemblyResolve and resolving the assembly like so 我可以通过在AppDomain.CurrentDomain.AssemblyResolve注册并像这样解析程序集来解决此问题

if (args.Name == "System")
{
     return typeof (ISet<>).Assembly;
}

but this seems very fragile to me, as it solves the problem for only this one specific assembly and I have to add another case for every assembly I need somewhere. 但这对我来说似乎很脆弱,因为它只能解决一个特定程序集的问题,并且我必须为某个地方需要的每个程序集添加另一个案例。

Does anyone have experience on how to solve this? 有没有人有解决此问题的经验? Any help is greatly appreciated! 任何帮助是极大的赞赏!

Similar problem was addressed in the following thread: How can I deserialize with TypeNameHandling.Objects in Json.NET Silverlight? 在以下线程中解决了类似的问题: 如何在Json.NET Silverlight中使用TypeNameHandling.Objects反序列化?

The problem seems to be that Json is failing to load the assembly with partial name. 问题似乎是Json无法用部分名称加载程序集。 You could overcome this issue by using TypeNameAssemblyFormat = FormatterAssemblyStyle.Full . 您可以通过使用TypeNameAssemblyFormat = FormatterAssemblyStyle.Full来解决此问题。

If you check the source code for NewtonSoft.Json in DefaultSerializationBinder.GetTypeNameFromTypeNameKey approx. 如果在DefaultSerializationBinder.GetTypeNameFromTypeNameKey中检查NewtonSoft.Json的源代码。 row 83.. It tries to get the type 第83行。它尝试获取类型

System.Collections.Generic.Dictionary 2[[System.String, mscorlib],[System.Collections.Generic.ISet 1[[System.String, mscorlib]], System]] System.Collections.Generic.Dictionary 2[[System.String, mscorlib],[System.Collections.Generic.ISet 1 [[System.String,mscorlib]],系统]]

from assembly 从组装

mscorlib.dll mscorlib.dll

Type type = assembly.GetType(typeName);

Which returns null. 返回空值。 This is with FormatterAssemblyStyle.Simple. 这与FormatterAssemblyStyle.Simple一起使用。

If you use FormatterAssemblyStyle.Full then the same type will be: 如果使用FormatterAssemblyStyle.Full,则相同的类型将是:

System.Collections.Generic.Dictionary 2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.ISet 1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] System.Collections.Generic.Dictionary 2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.ISet 1 [[System.String,mscorlib,Version = 4.0.0.0,文化=中性,PublicKeyToken = b77a5c561934e089,系统,版本= 4.0.0.0,文化=中性,PublicKeyToken = b77a5c561934e089]

And then: 接着:

Type type = assembly.GetType(typeName);

Will work and hence the deserialization works as well. 将起作用,因此反序列化也将起作用。

I cant say why this is the case though. 我不能说为什么是这种情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM