给定已知类型时,DataContractJsonSerializer中'type'参数的用途

时间:2014-07-16 18:07:24

标签: c# serialization

根据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参数中指定类型的任何对象。

我的问题是:

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

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

1 个答案:

答案 0 :(得分:0)

我相信这个想法是知道期望的类型将有助于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”属性。无论如何,这使我们无法摆脱风险。
  4. 因此,在非bug用法中,通常只是通过序列化来保留多态参数。

    此外,它不使用Type.IsAssignableFrom(Type),因为这不是必需的,并且会导致可能造成不必要的挫折的异常,因此当您的代码使用类型Type调用它并向其发送{{ 1}}要序列化,它正在检查是否TypeA,确定它不是预期的类型,并打印出额外的,不必要的类型信息。