zoukankan      html  css  js  c++  java
  • 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

    {...}

  • 相关阅读:
    开放源码的对象关系映射工具ORM.NET 插入数据 Insert/Update Data
    开放源码的对象关系映射工具ORM.NET 快档开发入门 Quick Start
    .NET 动态脚本语言Script.NET 开发指南
    开放源码的对象关系映射工具ORM.NET 删除数据 Deleting Records using ORM.NET
    .NET Remoting过时了吗?为什么公司的项目还是选择用.NET Remoting,而不是WCF?
    开放源码的对象关系映射工具ORM.NET 查看和显示数据 View and Display data using ORM.NET
    开放源码的对象关系映射工具ORM.NET 查询表 调用存储过程 增加自定义代码
    技术人生:坚持,每日一博
    CQRS:CQRS + DDD + MDP 实现快速应用程序开发
    NodeJs:Happy代码生成器,重构了代码,更新了文档,完善了示例,欢迎下载使用
  • 原文地址:https://www.cnblogs.com/lzjsky/p/2008128.html
Copyright © 2011-2022 走看看