[英]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.