序列化程序的设计方式是,如果它序列化一个对象,它应该能够读回它。如果您尝试序列化声明类型为“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] 属性帮助串行器将数据协定名称/命名空间映射到实际的 CLR 类型)。此外,如果您使用不同的语言/平台(即 Java)与服务通信,CLR 类型名称甚至没有意义。
另一个更详细的解释在帖子http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx - 它谈论的是[ServiceKnownType]而不是[KnownType],但原理是一样的。
最后,关于您的问题:它是否违反了 OO 原则?是的,这个原则被打破了,这是在你的分布式(面向服务的)应用程序中失去客户端和服务之间的耦合所要付出的代价。