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

时间:2014-05-14 10:38:07

标签: c# serialization dictionary set json.net

我正在尝试序列化(以及稍后反序列化)Dictionary<string, ISet<string>>。不幸的是,Json.NET(通过NuGet的v6.0.3)无法做到这一点。我的工作是

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);

变量json然后保存字符串

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

现在我想用

反序列化字符串
JsonConvert.DeserializeObject<IDictionary<string, ISet<string>>>(json, settings);

无法解析Dictionary类型,因为它无法找到System所属的ISet程序集。当我改为做以下

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

一切正常。因此,TypeNameHandling设置(更改/省略格式不会改变任何内容)似乎实际上会中断反序列化。

我发现,如果我没有设置TypeNameHandling设置,则会忽略序列化的$type属性。即,在反序列化时,类型信息仅取自解析它们的目标类型。这很有效。

设置TypeNameHandling时,类型解析通过Json.NET程序集中的反射发生,它不依赖于System程序集,因此无法解析ISet接口。我可以通过注册AppDomain.CurrentDomain.AssemblyResolve并像这样解决程序集来解决这个问题

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

但这对我来说似乎非常脆弱,因为它解决了这个特定程序集的问题,我必须为我需要的每个程序集添加另一个案例。

有没有人有如何解决这个问题的经验?非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

以下主题解决了类似的问题:How can I deserialize with TypeNameHandling.Objects in Json.NET Silverlight?

问题似乎是Json无法使用部分名称加载程序集。您可以使用TypeNameAssemblyFormat = FormatterAssemblyStyle.Full来解决此问题。

答案 1 :(得分:1)

如果在DefaultSerializationBinder.GetTypeNameFromTypeNameKey中检查NewtonSoft.Json的源代码。第83行。它试图获取类型

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

来自议会

mscorlib.dll中

Type type = assembly.GetType(typeName);

返回null。这与FormatterAssemblyStyle.Simple。

有关

如果使用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 =中性,PublicKeyToken = b77a5c561934e089]]

然后:

Type type = assembly.GetType(typeName);

可以工作,因此反序列化也可以。

我不能说为什么会这样。