【问题标题】:De-serialization issue in json.net when using BindingList使用 BindingList 时 json.net 中的反序列化问题
【发布时间】:2016-01-19 23:47:43
【问题描述】:

我们遇到这样一种情况,通过 json.net 进行序列化和反序列化的字段是我们其中一个对象的绑定列表属性。当试图反序列化这个字段时,我们得到一个异常:

Newtonsoft.Json.dll 中出现“Newtonsoft.Json.JsonSerializationException”类型的未处理异常

附加信息:JSON 'WpfApplication1.Wrapper1[[System.ComponentModel.BindingList1[[System.String, mscorlib]], System]], WpfApplication1'中指定的错误解析类型。路径“Potato.$type”,第 4 行,位置 131。

为了重现,我创建了一个小样本:

public class ClassToSerialize
{
    public Wrapper<BindingList<string>> Potato { get; set; }
}

public class Wrapper<T>
{
    public Wrapper()
    {
    }

    public Wrapper(T item)
    {
        Value = item;
    }

    #region Properties

    [JsonProperty]
    public T Value { get; set; }

    #endregion
}

测试是:

var objectToSerialize = new ClassToSerialize
{
    Potato = new Wrapper<BindingList<string>>(new BindingList<string>
    {
        "tomato",
        "basil"
    })
};

string serializedPotato = JsonSerializer<ClassToSerialize>.Serialize(objectToSerialize, true);
ClassToSerialize deserializedPotato = JsonSerializer<ClassToSerialize>.Deserialize(serializedPotato);

序列化代码在哪里:

public class JsonSerializer<T> where T : class
{
    public static string Serialize(T item, bool isComplexType = false)
    {
        if (isComplexType)
        {
            string serializedJson = JsonConvert.SerializeObject(item, Formatting.Indented, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Objects,
                TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
            });

            return serializedJson;
        }

        return JsonConvert.SerializeObject(item);
    }

    public static T Deserialize(string serializedItem)
    {
        var deserializedObject = JsonConvert.DeserializeObject<T>(serializedItem, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.Objects
        });

        return deserializedObject;
    }
}

错误发生在这里:ClassToSerialize deserializedPotato = JsonSerializer&lt;ClassToSerialize&gt;.Deserialize(serializedPotato); 但如果我将底层集合的类型从BindingList&lt;T&gt; 更改为List&lt;T&gt;,一切正常。

有谁知道这里的问题是什么以及如何解决它?

请注意,我已经测试了一个未包装的 BindingList&lt;&gt;(即未包装在另一种类型中)并且效果很好。

非常感谢,

【问题讨论】:

  • System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple 似乎有问题。如果我将其更改为FormatterAssemblyStyle.Full,问题就会消失。使用简单类型名称,在 DefaultSerializationBinder.GetTypeFromTypeNameKey() 内调用 Type.GetType() 会失败。不知道为什么;也许你应该report an issue
  • @dbc 谢谢。这解决了这个问题,但它略低于最佳状态。我会按照你的建议报告这个问题。非常感谢你,如果你写你的评论作为答案,我很乐意接受。

标签: c# json.net


【解决方案1】:

使用FormatterAssemblyStyle.Simple 似乎有问题。如果我修改您的代码以使用FormatterAssemblyStyle.Full,问题就会消失。

使用简单的程序集名称(在 Json.NET 8.0.2 中),即使程序集是正确的,对 DefaultSerializationBinder.GetTypeFromTypeNameKey(TypeNameKey typeNameKey) 内部的 assembly.GetType(typeName) 的调用也会失败。

我不完全确定调用失败的原因,因为所有通用参数类型都存在简单的程序集名称。 Assembly.GetType(string) 的文档没有指定如何发现泛型类型名称引用的程序集。 Type.GetType(string) 的文档指出:

GetType 仅适用于从磁盘加载的程序集。

后来:

如果 typeName 包含命名空间但不包含程序集名称,则此方法仅按此顺序搜索调用对象的程序集和 Mscorlib.dll。如果 typeName 是完全限定的部分或完整程序集名称,则此方法在指定的程序集中进行搜索。如果程序集具有强名称,则需要完整的程序集名称。

所以问题可能是BindingList&lt;T&gt; 不在 mscorlib.dll 中(得到特殊处理),也不在从磁盘加载的 DLL 中(它来自 GAC 中的 System.dll)?

我可以手动重现这种不一致。如果我这样做:

Type.GetType("System.Collections.Generic.List`1[[System.String, mscorlib]],mscorlib")

它有效。然而,

Type.GetType("System.ComponentModel.BindingList`1[[System.String,mscorlib]],System")

失败。

也许你可以report an issue

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    相关资源
    最近更新 更多