首页 文章

Data Contract Serializer要求超类了解子类

提问于
浏览
1

我遇到了这个问题,“反序列化器没有任何类型的知识可以映射到这个 Contract ”在谷歌上搜索后,我达到了这个帖子

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

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

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

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

2 回答

  • 2

    串行器的设计方式是,如果它序列化一个对象,它应该能够读回来 . 如果您尝试序列化具有声明类型“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类型名称就可以与另一种语言/平台(即Java)中的服务进行通信,因此CLR类型名称甚至没有意义 .

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

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

  • 3

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

相关问题