Windows Communication Foundation介绍(四)
六、定义DataContract
我在介绍如何定义一个ServiceContract时,举了这样的一个例子,代码如下:
- [ServiceContract]
- public class BookTicket
- {
- [OperationContract]
- public bool Check(Ticket ticket)
- {
- bool flag;
- //logic to check whether the ticket is none;
- return flag;
- }
- [OperationContract]
- private bool Book(Ticket ticket)
- {
- //logic to book the ticket
- }
- }
在. Net中,除了基本类型如int,long,double,以及枚举类型和String类型外,一个自定义的类型如要支持序列化操作,应该标记该类型为 [Serializable],或者使该类型实现ISerializable接口。而在WCF中,推荐的一种方式是为这些类型标记 DataContractAttribute。方法如下:
- [DataContract]
- public class Ticket
- {
- private string m_movieName;
- [DataMember]
- public int SeatNo;
- [DataMember]
- public string MovieName
- {
- get {return m_movieName;}
- set {m_movieName = value;}
- }
- [DataMember]
- private DateTime Time;
- }
当我们为一个类型标注DataContractAttribute时,只有被显式标注了 DataMemberAttribute的成员方才支持序列化操作。这一点与SerializableAttribute大相径庭。一个被标记了 SerializableAttribute的类型,在默认情况下,其内部的成员,不管是public还是private都支持序列化,除非是那些被施加 了NonSerializedAttribute的成员。DataContractAttribute采用这种显式标注法,使得我们更加专注于服务消息的 定义,只有需要被传递的服务消息成员,方才被标注DataMemberAttribute。
如果DataContract类中的DataMember成员包含了泛型,那么泛型类型参数必须支持序列化,如下代码所示:
- [DataContract]
- public class MyGeneric<T>
- {
- [DataMember]
- public T theData;
- }
- MyGeneric<int> intObject = new MyGeneric();
- MyGeneric<Custom> customObject = new MyGeneric();
DataContract 以Namespace和Name来唯一标识,我们可以在DataContractAttribute的Namespace属性、Name属性中进行设置。 如未设置DataContract的Name属性,则默认的名字为定义的类型名。DataMember也可以通过设置Name属性,默认的名字为定义的成 员名。如下代码所示:
- namespace MyCompany.OrderProc
- {
- [DataContract]
- public class PurchaseOrder
- {
- // DataMember名字为默认的Amount;
- [DataMember]
- public double Amount;
- // Name属性将重写默认的名字Ship_to,此时DataMember名为Address;
- [DataMember(Name = "Address")]
- public string Ship_to;
- }
- //Namespace为默认值:
- // http:schemas.datacontract.org/2004/07/MyCompany.OrderProc
- //此时其名为PurchaseOrder而非MyInvoice
- [DataContract(Name = "PurchaseOrder")]
- public class MyInvoice
- {
- // Code not shown.
- }
- // 其名为Payment而非MyPayment
- // Namespace被设置为http:schemas.example.com/
- [DataContract(Name = "Payment",
- Namespace = "http:schemas.example.com/")]
- public class MyPayment
- {
- // Code not shown.
- }
- }
- // 3.0 的语法?
- [assembly:ContractNamespace(
- ClrNamespace = "MyCorp.CRM",
- Namespace= "http:schemas.example.com/crm")]
- namespace MyCorp.CRM
- {
- // 此时Namespace被设置为http:schemas.example.com/crm.
- // 名字仍然为默认值Customer
- [DataContract]
- public class Customer
- {
- // Code not shown.
- }
- }
1、默认的顺序依照字母顺序;
2、如成员均通过Order属性指定了顺序,且顺序值相同,则以字母顺序;
3、未指定Order属性的成员顺序在指定了Order顺序之前;
4、如果DataContract处于继承体系中,则不管子类中指定的Order值如何,父类的成员顺序优先。
下面的代码很好的说明了DataMember的顺序:
- [DataContract]
- public class BaseType
- {
- [DataMember] public string zebra;
- }
- [DataContract]
- public class DerivedType : BaseType
- {
- [DataMember(Order = 0)] public string bird;
- [DataMember(Order = 1)] public string parrot;
- [DataMember] public string dog;
- [DataMember(Order = 3)] public string antelope;
- [DataMember] public string cat;
- [DataMember(Order = 1)] public string albatross;
- }
- <DerivedType>
- <zebra/>
- <cat/>
- <dog/>
- <bird/>
- <albatross/>
- <parrot/>
- <antelope/>
- </DerivedType>
判断两个DataContract是否相同,应该根据DataContract的Namespace和Name,以及DataMember的Name和Order来综合判断。例如下面代码所示的类Customer和Person其实是同一个DataContract:
- [DataContract]
- public class Customer
- {
- [DataMember]
- public string fullName;
- [DataMember]
- public string telephoneNumber;
- }
- [DataContract(Name=”Customer”)]
- public class Person
- {
- [DataMember(Name = "fullName")]
- private string nameOfPerson;
- private string address;
- [DataMember(Name= "telephoneNumber")]
- private string phoneNumber;
- }
- [DataContract(Name= "Coordinates")]
- public class Coords1
- {
- [DataMember] public int X;
- [DataMember] public int Y;
- }
- [DataContract(Name= "Coordinates")]
- public class Coords2
- {
- [DataMember] public int Y;
- [DataMember] public int X;
- }
- [DataContract(Name= "Coordinates")]
- public class Coords3
- {
- [DataMember(Order=2)] public int Y;
- [DataMember(Order=1)] public int X;
- }
- [DataContract(Name= "Coordinates")]
- public class Coords4
- {
- [DataMember(Order=1)] public int Y;
- [DataMember(Order=2)] public int X;
- }
举例来说,如果我们定义了这样三个类:
- [DataContract]
- public class Shape { }
- [DataContract(Name = "Circle")]
- public class CircleType : Shape { }
- [DataContract(Name = "Triangle")]
- public class TriangleType : Shape { }
- [DataContract]
- public class CompanyLogo
- {
- [DataMember]
- private Shape ShapeOfLogo;
- [DataMember]
- private int ColorOfLogo;
- }
- [DataContract]
- [KnownType(typeof(CircleType))]
- [KnownType(typeof(TriangleType))]
- public class CompanyLogo
- {
- [DataMember]
- private Shape ShapeOfLogo;
- [DataMember]
- private int ColorOfLogo;
- }
- public interface ICustomerInfo
- {
- string ReturnCustomerName();
- }
- [DataContract(Name = "Customer")]
- public class CustomerType : ICustomerInfo
- {
- public string ReturnCustomerName()
- {
- return "no name";
- }
- }
- [DataContract]
- [KnownType(typeof(CustomerType))]
- public class PurchaseOrder
- {
- [DataMember]
- ICustomerInfo buyer;
- [DataMember]
- int amount;
- }
对 于集合类型也有相似的规定。例如Hashtable类型,其内存储的均为object对象,但实际设置的值可能是一些自定义类型,此时也许要通过 KnownType进行标注。例如在类LibraryCatalog中,定义了Hashtable类型的字段theCatalog。该字段可能会设置为 Book类型和Magazine类型,假定Book类型和Magazine类型均被定义为DataContract,则类LibraryCatalog的 正确定义应如下所示:
- [DataContract]
- [KnownType(typeof(Book))]
- [KnownType(typeof(Magazine))]
- public class LibraryCatalog
- {
- [DataMember]
- System.Collections.Hashtable theCatalog;
- }
- [DataContract]
- [KnownType(typeof(int[]))]
- public class MathOperationData
- {
- private object numberValue;
- [DataMember]
- public object Numbers
- {
- get { return numberValue; }
- set { numberValue = value; }
- }
- //[DataMember]
- //public Operation Operation;
- }
- static void Run()
- {
- MathOperationData md = new MathOperationData();
- int a = 100;
- md.Numbers = a;
- int[] b = new int[100];
- md.Numbers = b;
- List c = new List();
- md.Numbers = c;
- }
- static void Run()
- {
- MathOperationData md = new MathOperationData();
- ArrayList d = new ArrayList();
- md.Numbers = d;
- }
- [DataContract]
- [KnownType(typeof(CircleType))]
- [KnownType(typeof(TriangleType))]
- public class MyDrawing
- {
- [DataMember]
- private object Shape;
- [DataMember]
- private int Color;
- }
- [DataContract]
- public class DoubleDrawing : MyDrawing
- {
- [DataMember]
- private object additionalShape;
- }
注: KnowTypeAttribute可以标注类和结构,但不能标注接口。此外,DataContract同样不能标注接口,仅可以标注类、结构和枚举。要 使用DataContractAttribute、DataMemberAttribute和KnownTypeAttribute,需要添加WinFx 版本的System.Runtime.Serialization程序集的引用。