'类型'当给定已知类型时,在DataContractJsonSerializer中

本文关键字:类型 DataContractJsonSerializer | 更新日期: 2023-09-27 18:13:23

对于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参数中指定类型的对象。

我的问题是

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

是否有特殊情况,第一个参数被区别对待,或者对序列化器有特殊用途?

'类型'当给定已知类型时,在DataContractJsonSerializer中

我相信这个想法是,知道什么类型是预期将有助于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"属性。这使我们尽可能地摆脱了风险。

所以在无bug的使用中,它主要只是通过序列化来保持多态参数的问题。

此外,它不使用Type.IsAssignableFrom(Type),因为这是不必要的,会导致异常,可能会造成不必要的挫折,所以当你的代码用Type类型调用它并向它发送TypeA来序列化时,它正在检查Type == value.GetType(),决定它不是预期的类型,并打印出额外的,不必要的类型信息。