【问题标题】:Purpose of 'type' argument in DataContractJsonSerializer when given known types给定已知类型时 DataContractJsonSerializer 中“类型”参数的目的
【发布时间】:2014-07-17 02:35:59
【问题描述】:

根据 MSDN,构造函数的第一个参数 DataContractJsonSerializer(Type, IEnumerable<Type>) 被定义为被序列化或反序列化的实例的类型

然而,我最近在一些产品代码中遇到了一个错误,但很快意识到序列化按预期工作。一个简化的版本是:

var knownTypes = new[] { typeof(TypeA), typeof(TypeB) };

// Bug below. Should be 'otherType = typeof(C)'
// Always sets otherType to System.RuntimeType
var otherType = typeof(TypeC).GetType();

var serializer = new DataContractJsonSerializer(otherType, knownTypes);

using(var output = new MemoryStream())
{
    serializer.WriteObject(output, new TypeA());
    output.Position = 0;
    var copy = (TypeA) serializer.ReadObject(output);
}

这是因为序列化程序将成功写入具有type 参数knownTypes 参数中指定的类型的任何对象。

我的问题是:

如果序列化程序可以正确写入任一参数中指定的类型的对象,那么使用第一个参数的目的是什么?

是否存在第一个参数被不同处理或对序列化程序有特殊用途的特殊情况?

【问题讨论】:

    标签: c# serialization


    【解决方案1】:

    我相信这个想法是知道什么类型是预期将有助于DataContractJsonSerializer在多态操作的情况下打印出类型信息。

    class Foo
    {
        public string a { get; set; }
    }
    
    class Bar : Foo
    {
        public string b { get; set; }
    }
    

    假设对于我的其余示例,您按如下方式初始化序列化程序:

    var s = new DataContractJsonSerializer(typeof(Foo), new Type[] { typeof(Bar) });
    s.EmitTypeInformation = EmitTypeInformation.AsNeeded;
    

    做完之后,你就开始使用它了:

    1. 完成此操作后,将Foo 的实例传递给它以进行序列化,它将序列化单个属性a,就是这样。 { "a" : "valueA" }
    2. 现在,您将Bar 的实例传递给它。等等,typeof(Foo) != typeof(Bar)。序列化程序看到了这一点,并认识到反序列化客户端可能会被它弄糊涂,或者最好的情况是,可以简单地跳过一些数据。因此,它打印出显式类型信息。 { "__type" : "Bar", "a : "valueA", "b", "valueB" }
    3. 现在假设您传递给它一个完全随机的实例,例如DateTime。再次,它检查并看到,哇,typeof(DateTime) != typeof(Foo),所以这里客户端可能会严重感到困惑。因此,再次添加了“__type”属性。这让我们尽可能地摆脱了风险。

    所以在非错误使用中,主要只是通过序列化保留多态参数的问题。

    此外,它不使用Type.IsAssignableFrom(Type),因为这不是必需的,并且会导致可能不必要的挫败的异常,因此当您的代码使用Type 类型调用它并发送TypeA 以进行序列化时,它正在检查Type == value.GetType(),确定它不是预期的类型,并打印出额外的、不必要的类型信息。

    【讨论】:

    • EmitTypeInformation 属性非常好。我什至没有想到这一点,因为我们的系统仍在 .NET 4.0 中,该属性不可用。我要指出,尝试序列化派生类型 Bar 会引发异常,除非您将其指定为 knownType
    • 其实我觉得类型信息就是答案。在 4.0 中,默认情况下发出类型信息是“AsNeeded”。第一个type参数,有一个特殊的含义,如果要序列化的对象匹配,写入时会跳过类型信息。
    • 啊,是的,我忘记了这些。我不久前切换到 JSON.net,所以我还没有习惯这些东西。这样更好,对吧?我在打电话,所以检查文档很困难。
    猜你喜欢
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 2021-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    • 2012-02-14
    相关资源
    最近更新 更多