Data Contract Serializer要求超类了解子类

时间:2011-06-25 04:29:22

标签: silverlight wcf oop windows-phone-7 datacontractserializer

我遇到了这个问题, “解串器没有任何类型的知识可以映射到这个合同” 谷歌搜索后,我到达了这篇文章

The deserializer has no knowlege of any type that maps to this contract

答案说,基类必须声明“KnownTypes”之类的 [DataContract,KnownType(typeof(Subclass))...],

如果我必须在我的父类中声明这个,[DataContract,KnownType(typeof(Subclass))],它是否违反了父类不必了解子类的OO设计原则?

这样做的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

序列化程序的设计方式是,如果它序列化一个对象,它应该能够读回来。如果您尝试序列化具有声明类型“Base”的对象,但实际类型为“Derived”(请参见下面的示例),如果您希望能够从序列化对象中读回“Derived”的实例,你需要以某种方式注释XML,该实例不是它所声明的类型。

[DataContract]
public class MyType
{
    [DataMember]
    public object obj = new Derived();
}

该类型的序列化版本看起来类似于以下XML:

<MyType>
  <obj actualType="Derived">
    <!-- fields of the derived type -->
  </obj>
</MyType>

当反序列化类型时,序列化程序将查看“actualType”(非实际名称)属性,并且必须找到该类型,初始化它并设置其属性。让序列化程序(在Silverlight中生存的是一个受信任的程序集并拥有比普通用户代码更多的“权限”)来创建任意类型是一个潜在的安全问题,因此这是限制可以反序列化的类型的一个原因。并且基于序列化器的设计(如果我们可以序列化它,我们应该能够反序列化它),序列化也因为这个原因而失败。

另一个问题是序列化数据通常用于不同服务之间,不同计算机之间以及可能使用不同语言之间的通信。您可能(通常情况下)在客户端的命名空间中有一个类,它与服务器端的类具有类似的数据协定,但它们具有不同的名称和/或驻留在不同的名称空间中。因此,简单地在“actualType”属性中添加CLR类型名称在这种情况下也不起作用([KnownType]属性帮助serialzier将数据协定名称/名称空间映射到实际的CLR类型)。此外,如果您正在使用不同语言/平台(即Java)与服务进行通信,则CLR类型名称甚至没有意义。

另一个更详细的解释在帖子http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx给出 - 它讨论[ServiceKnownType]而不是[KnownType],但原则是相同的。

最后,关于你的问题:它是否打破了OO原则?是的,这个原则被打破了,这是为了能够在分布式(面向服务的)应用程序中丢失客户端和服务之间的耦合而付出的代价。

答案 1 :(得分:2)

是的,它打破了OO设计的原则。这是因为SOA是关于共享契约(服务的ABC中的C)而不是类型,而OO是关于类型层次结构。这样认为服务的客户端可能甚至不是OO语言,但仍然可以应用SOA原则。如何在服务器端完成映射是一个实现问题。