WCF技术剖析之十四:泛型数据契约和集合数据契约(上篇)2012-10-25 博客园 Artech在.NET Framework 2.0中,泛型第一次被引入。我们可以定义泛型接口、泛型类型、泛型委托和泛型方法。序列化依赖于真实具体的类型,而泛型则刻意模糊了具体类型概念。而集合代表一组对象的组合,集合具有可迭代(Enumerable)的特性,可以通过某个迭代规则遍历集合中的每一个元素。由于范型类型和集合类型在序列化和反序列化上具有一些特殊的行为和规则,在这篇文章中,我将会对此进行详细介绍。上篇先来说所泛型数据契约。一、泛型与数据契约面向对象通过继承实现了代码的重用,而泛型则实现了“算法的重用”。我们定义一种算法,比如排序、搜索、交换、比较或者转换等等,为了实现尽可能的重用,我们并不限定该算法操作对象的具体类型,而通过一个泛型类型来表示。在真正创建范型对象或者调用该方法的时候,才指定其具体的类型。就实现来说,泛型是CLR和编程语言(或者是基于编程语言的编译器)共同实现的一种特殊机制;就泛型的概念来说,这是面向对象的范畴。而我们现在介绍的数据契约,则属于面向服务的概念。两者具有一些冲突 ,比如面常服务没有继承、重载的概念一样,面向服务同样也无法理解泛型。但是基于WCF的编程语言是C#、VB.NET这样的完全面向对象的编程语言,而WCF服务却是基于面向服务的。所以,从某种意义上讲,WCF的一个重大的作用就是弥合面向对象编程(OOP)和面向服务架构(SOA)之间的差异。我们现在就来看看WCF做了些什么使我们能够以泛型类型的形式来定义数据契约。二、泛型数据契约的默认序列化规则我们首先通过一个简单的例子看看DataContractSerializer是如何序列化一个范型对象的。为此我定义一个泛型类型Bill<BillHeader, BillDetail>,代表一个一般意义上的单据,BillHeader和BillDetail代表单据报头的明细的类型。两个属性Header和Details表示单据报头和明细列表。
1: namespace Artech.DataContractSerializerDemos
2: {
3: [DataContract(Namespace="http://www.artech.com/")]
4: public class Bill<BillHeader, BillDetail>
5: {
6: [DataMember(Order = 1)]
7: public BillHeader Header
8: { get; set; }
9:
10: [DataMember(Order = 2)]
11: public BillDetail[] Details
12: { get; set; }
13: }
14: }
然后我们定义用于描述订单单据的报头和明细的类型:OrderBillHeader和OrderBillDetail。OrderBillHeader描述定单的总体信息,OrderBillDetail实际上表示订单中每一个产品的ID、单价和数量。
1: namespace Artech.DataContractSerializerDemos
2: {
3: [DataContract(Namespace="http://www.artech.com/")]
4: public class OrderBillHeader
5: {
6: [DataMember]
7: public Guid OrderID
8: { get; set; }
9:
10: [DataMember]
11: public DateTime Date
12: { get; set; }
13:
14: [DataMember]
15: public string Customer
16: { get; set; }
17: }
18:
19: [DataContract(Namespace="http://www.artech.com/")]
20: public class OrderBillDetail
21: {
22: [DataMember]
23: public Guid ProductID
24: { get; set; }
25:
26: [DataMember]
27: public int Quantity
28: { get; set; }
29:
30: [DataMember]
31: public double UnitPrice
32: { get; set; }
33: }
34: }
通过下面一个方法创建泛型类型Bill<BillHeader, BillDetail>对象,泛型类型指定为上面定义的OrderBillHeader和OrderBillDetail。
1: private static Bill<OrderBillHeader, OrderBillDetail> CreateOrderBill()
2: {
3: OrderBillHeader header = new OrderBillHeader
4: {
5: OrderID = Guid.NewGuid(),
6: Date = DateTime.Today,
7: Customer = "Foo"
8: };
9:
10: IList<OrderBillDetail> details = new List<OrderBillDetail>();
11: OrderBillDetail detail = new OrderBillDetail
12: {
13: ProductID = Guid.NewGuid(),
14: Quantity = 20,
15: UnitPrice = 888
16: };
17: details.Add(detail);
18: detail = new OrderBillDetail
19: {
20: ProductID = Guid.NewGuid(),
21: Quantity = 10,
22: UnitPrice = 9999
23: };
24: details.Add(detail);
25:
26:
27: Bill<OrderBillHeader, OrderBillDetail> orderBill = new Bill<OrderBillHeader, OrderBillDetail>()
28: {
29: Header = header,
30: Details = details.ToArray<OrderBillDetail>()
31: };
32: return orderBill;
33: }