• WCF Data Contract之KnownType


    1 使用场合:

    WCF Data Contract中如果存在向下造型的情况时你就会用到 KnownTypeAttribute类以保证在反序列化时引擎能知道应该使用哪个具体的类型。主要有以下几种典型的情况:

    1 发送的数据契约类型 是从接收端期望接收的数据契约类型继承的。

    2 声明的数据类型是接口(注意:集合接口除外,具体请看稍后的 WCF Data Contract之集合类型

    3 声明的数据类型是 Object.

    4 在数据契约中的数据 成员包含前面三种的任何一种时。例如:在 Hashtable内部使用 Object来保存实际对象,所以在接收端并不能确定其中对象的实际类型 ,此时你需要增加 KnownType来告诉反序列化引擎应该使用哪个具体的类型。

    [DataContract]

    public class ClassA

    {

        [DataMember]

        public string name;

    }

    [DataContract]

    public class ClassB : ClassA

    {

        [DataMember]

        public int department;

        [DataMember]

        public string title;

        [DataMember]

        public int salary;

    }

    Public interface InterfaceA

    {

        String GetSomething();

    }

    [DataContract]

    Public calss ImplA:InterfaceA

    {  

         Public String GetSomething()

    {

        Return “don’t know”;

    }

    }

     

    [DataContract]

    Public calss ImplB:InterfaceA

    {  

         Public String GetSomething()

    {

        Return “don’t know”;

    }

    }

     

    [DataContract]

    Public class ClassC{}

     

    [DataContract]

    Public class ClassD{}

     

    [DataContract]

    Public class ClassWillProcess

    {

    [DataMember]

    ClassA ca;

     

    [DataMember]

    InterfaceA ia;

     

    [DataMember]

    ArrayList arraylist1;

     

    [DataMember]

    Object numberValue;

    }

    大家请注意 ClassWillProcessl类型,我们需要增加哪些类型到 KnownType中呢?

    1 如果我们在应用中可能将 ClassB的实例赋值给 ca的 话,我们需要增加 ClassB KnowType中( [KnowType(typeof(ClassB))] ),因为 ClassB派生于 ClassA,所以在反序列化时存在向下造型。如果不存 在这种可能性的话,可以不加。

     

    2 由于 ia的声明类 型是一个接口,所以我们需要将接口的实现类加到 KnownType中。在 这里是 ImplA ImplB。试想一下,如果我们只增加了 ImplA KnownType中, 并且我们将 ImplB的实例赋给了 ia,反序列化引擎还是会将其反序列化成 ImplA,因为它只知道 ImplA.

    3 如果我们 arraylist1 集合中可能会将 ClassC ClassD放入其中,由于非泛型集合都是使用 Object来保存实际对象,所以我们也需要将 ClassC ClassD加入 到 KnownType中。

    4 如果我们也希望将一个 int的数组存放在 numberValue中(当然在实际情况中很少 发生),我么也需要将 int[]加入到 KnownType中。

    增加了 KnownType ClassWillProcessl类型如下:

    [DataContract]

    [KnowType(typeof(ClassB))]

    [KnowType(typeof(ImplA))]

    [KnowType(typeof(ImplB))]

    [KnowType(typeof(ClassC))]

    [KnowType(typeof(ClassD))]

    [KnowType(typeof(int[]))]

    Public class ClassWillProcess

    {

    [DataMember]

    ClassA ca;

     

    [DataMember]

    InterfaceA ia;

     

    [DataMember]

    ArrayList arraylist1;

     

    Object numberValue;

     

    [DataMember]

    Public object Numbers

    {

       get {return numberValue;}

       set {numberValue=value;}

    }

    }

    注:如果对 numberValue赋值时,以下语句都是可以接受的:

                   ClassWillProcess cwp=new ClassWillProcess();

              // 因为 int 是基本类型,对于反序列化引擎来说总是 Known Type

              int a=10; cwp.Numbers= a;

              // 因为 int 数组已经增加到 knownType 中去了

             int[] b=new int[100];cwp.Numbers =b;

             //List<int> ArrayList 是等价的

             List<int> c=new List<int>(); cwp.Numbers=c;

             ArrayList d=new ArrayList(); cwp.Numbers=d;

    2 使用规则:

        2.1 基本类型(如: int,bool)以及被认为是基本类型的某些类型(如: DateTime,XmlElement DateTimeOffset结构并没有被认为是基本类型)对于反序列化引擎来说总是可知的,不需要通过这种机制来将其加到 KnownType中去。但是基本类型的 Array必须通过这种方式显示的增加,非泛型集合是和 Object的数组是等价的。

    2.2 同一类型在同一个命名空间只能用 KnownTypeAttribute应用一次。

    2.3 KnownType只能和类和结构进 行关联,不能和接口进行关联。

    2.4 KnownType属性是可以继承的。例如:前面 ClassWillProcess 类使用了 KnownType, 如果我们有一个新类派生与 ClassWillProcess 类,我们就不需要在派生类中再添加在 ClassWillProcess 类已经添加了的 KnownType .

    2.5 KnownType 的类型参数不能是泛型。但是我 们可以通过定义一个方法并把这个方法名作为 KnownType 参数来解决此问题,但这个方法必须满足以下条件:

         a 必须是 static, 因为需要在对象实例化之前调用。

         b 必须是不带任何参数的。

         C 返回类型必须是可被 IEnumerable 接受的,(也就 是实现了 IEnumerable 接口的)。

        同时还必须满足一个类型只能有一个带有方法名参数的 KnownType ,不能再有其他的带有实际类型的 KnownType 应用。如下例 theDrawing 包含 ColorDrawing BlackAndWhiteDrawing 泛型的实例,并且它们都是继承 GenericDrawing 泛型。

    [DataContract]

    [KnownType("GetKnownType")]

    public class DrawingRecord2<T>

    {                

        [DataMember]

        private T TheData;

        [DataMember]

        private GenericDrawing<T> TheDrawing;

        private static Type[] GetKnownType()

        {

            Type[] t = new Type[2];

            t[0] = typeof(ColorDrawing<T>);

            t[1] = typeof(BlackAndWhiteDrawing<T>);

            return t;

        }

    }

    3 其他增加KnownType的方法

      3.1 你可以增加类型到ReadOnlyCollection集合中,然后通过 DataContractSerializer的KnownTypes属性来访问。

       3.2 也可以通过配置文件的<System.runtime.serialization>节 来增加KnownType,例如:

    <system.runtime.serialization>

       <dataContractSerializer>

          <declaredTypes>

             <add type = "Contact,Host,Version=1.0.0.0,Culture=neutral,

                                                                  PublicKeyToken=null">

                <knownType type = "Customer,MyClassLibrary,Version=1.0.0.0,

                                                 Culture=neutral,PublicKeyToken=null"/>

             </add>

          </declaredTypes>

       </dataContractSerializer>

    </system.runtime.serialization>

    3.3 前面介绍的KnowTypeAttribute是基于DataContract的,我们也可以使用 ServiceKnowTypeAttribute来基于ServiceContract或 OperationContract来设置 KnowType类,例如针对某一个服务操作:

    [DataContract]

    class Contact

    {...}

    [DataContract]

    class Customer : Contact

    {...}

    [ServiceContract]

    interface IContactManager

    {

       [OperationContract]

       [ServiceKnownType(typeof(Customer))]

       void AddContact(Contact contact);

       [OperationContract]

       Contact[] GetContacts( );

    }

        针对整个服务:

    [ServiceContract]

    [ServiceKnownType(typeof(Customer))]

    interface IContactManager

    {

       [OperationContract]

       void AddContact(Contact contact);

       [OperationContract]

       Contact[] GetContacts( );

    }

    注意:不管应用 ServiceKnowType是在服务级别还是在操作级别,最后导出到元数据中,都是将KnowType应用在基类中,如上述例子中的导入契约定义为:

    [DataContract]

    [KnownType(typeof(Customer))]

    class Contact

    {...}

    [DataContract]

    class Customer : Contact

    {...}

    [ServiceContract]

    interface IContactManager

    {...}

    作者:Angelo Lee
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    不通过App Store,在iOS设备上直接安装应用程序(转)
    Quest Central for DataBase 5.0.1,6.1 (软件+注册)
    微信公众号自定义菜单与关键词自动回复互斥解决
    转载《Spring AOP中pointcut expression表达式解析 及匹配多个条件》
    ssm 动态切换数据源
    spring aop
    微信公众号自动回复
    转载《spring定时任务轮询(spring Task)》
    N 秒打开一个新窗口
    java webservice maven spring Class Not Found Exception解决
  • 原文地址:https://www.cnblogs.com/yefengmeander/p/2887754.html
Copyright © 2020-2023  润新知