[爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道《天天山海经》为此录制的节目视频(苏州话)]]在.NET中,所有的集合都实现了IEnumerable接口,比如Array、Hashtable、ArrayList、Stack、Queue等。有的集合要求元素具有相同的类型,这种集合一般通过泛型的方式定义,它们实现另一个接口IEnumerable<T>(IEnumerable<T>本身继承自IEnumerable),这样的集合有List<T>、Dictionary<TKey,TValue>、Stack<T>、Queue<T>等。基于集合类型的序列化具有一些特殊的规则和行为,在上篇中我们详细介绍了基于泛型数据契约的序列化规则,接下来我们介绍基于集合对象的序列化,以及基于集合类型的服务操作。
一、IEnumerable<T>、Array与IList<T>
一个集合对象能够被序列化的前提是集合中的每个元素都能被序列化,也就是要求元素的类型是一个数据契约(或者是应用了SerialiableAttribute特性)。虽然集合具有各种各样的表现形式,由于其本质就是一组对象的组合,DataContractSerializer在对它们进行序列化的时候,采用的序列化规则和序列化过程中表现出来的行为是相似的。比如我们现在需要通过DataContractSerializer序列化一个Customer对象的集合,Customer类型定义如下。
1: namespace Artech.DataContractSerializerDemos
<!--CRLF-->
2: {
<!--CRLF-->
3: [DataContract(Namespace="http://www.artech.com/")]
<!--CRLF-->
4: public class Customer
<!--CRLF-->
5: {
<!--CRLF-->
6: [DataMember(Order = 1)]
<!--CRLF-->
7: public Guid ID
<!--CRLF-->
8: { get; set; }
<!--CRLF-->
9:
<!--CRLF-->
10: [DataMember(Order=2)]
<!--CRLF-->
11: public string Name
<!--CRLF-->
12: { get; set; }
<!--CRLF-->
13:
<!--CRLF-->
14: [DataMember(Order = 3)]
<!--CRLF-->
15: public string Phone
<!--CRLF-->
16: { get; set; }
<!--CRLF-->
17:
<!--CRLF-->
18: [DataMember(Order = 4)]
<!--CRLF-->
19: public string CompanyAddress
<!--CRLF-->
20: { get; set; }
<!--CRLF-->
21: }
<!--CRLF-->
22: }
<!--CRLF-->
现在我通过我们前面定义的范型Serialize<T>对以下3种不同类型的集合对象进行序列化:IEnumerable<Customer>、IList<Cusomter>和Customer[]。
1: Customer customerFoo = new Customer
<!--CRLF-->
2: {
<!--CRLF-->
3: ID = Guid.NewGuid(),
<!--CRLF-->
4: Name = "Foo",
<!--CRLF-->
5: Phone = "8888-88888888",
<!--CRLF-->
6: CompanyAddress = "#9981, West Sichuan Rd, Xian Shanxi Province"
<!--CRLF-->
7: };
<!--CRLF-->
8:
<!--CRLF-->
9: Customer customerBar = new Customer
<!--CRLF-->
10: {
<!--CRLF-->
11: ID = Guid.NewGuid(),
<!--CRLF-->
12: Name = "Bar",
<!--CRLF-->
13: Phone = "9999-99999999",
<!--CRLF-->
14: CompanyAddress = "#3721, Taishan Rd, Jinan ShanDong Province"
<!--CRLF-->
15: };
<!--CRLF-->
16: Customer[] customerArray = new Customer[] { customerFoo, customerBar };
<!--CRLF-->
17: IEnumerable<Customer> customerCollection = customerArray;
<!--CRLF-->
18: IList<Customer> customerList = customerArray.ToList<Customer>();
<!--CRLF-->
19:
<!--CRLF-->
20: Serialize<Customer[]>(customerArray, @"E:\Customer.Array.xml");
<!--CRLF-->
21: Serialize<IEnumerable<Customer>>( customerCollection, @"E:\Customer.GenericIEnumerable.xml");
<!--CRLF-->
22: Serialize<IList<Customer>>( customerList, @"E:\Customer.GenericIList.xml);
<!--CRLF-->
我们最终发现,虽然创建DataContractSerializer对象使用的类型不一样,但是最终序列化生成出来的XML却是完全一样的,也就是说DataContractSerializer在序列化这3种类型对象时,采用完全一样的序列化规则。从下面的XML的结构和内容中,我们可以总结出下面3条规则:
- 根节点的名称以ArrayOf为前缀,后面紧跟集合元素类型对应的数据契约名称;
- 集合元素对象用数据契约的命名空间作为整个集合契约的命名空间;
- 每个元素对象按照其数据契约定义进行序列化。
1: <ArrayOfCustomer xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.artech.com/">
<!--CRLF-->
2: <Customer>
<!--CRLF-->
3: <ID>8baed181-bcbc-493d-8592-3e08fd5ad1cf</ID>
<!--CRLF-->
4: <Name>Foo</Name>
<!--CRLF-->
5: <Phone>8888-88888888</Phone>
<!--CRLF-->
6: <CompanyAddress>#9981, West Sichuan Rd, Xian Shanxi Province</CompanyAddress>
<!--CRLF-->
7: </Customer>
<!--CRLF-->
8: <Customer>
<!--CRLF-->
9: <ID>2fca9719-4120-430c-9dc2-3ef9dc7dffb1</ID>
<!--CRLF-->
10: <Name>Bar</Name>
<!--CRLF-->
11: <Phone>9999-99999999</Phone>
<!--CRLF-->
12: <CompanyAddress>#3721, Taishan Rd, Jinan ShanDong Province</CompanyAddress>
<!--CRLF-->
13: </Customer>
<!--CRLF-->
14: </ArrayOfCustomer>
<!--CRLF-->
我们从根节点的名称ArrayOfCustomer,可以看出WCF将这个3个类型的对象IEnumerable<Customer>、IList<Cusomter>和Customer[]都作为Customer数组了。实际上,如果你在定义服务契约的时候,将某个服务操作的参数类型设为IEnumerable<T>或者<IList>,默认导出生成的服务契约中,相应的参数类型就是数组类型。 比如,在同一个服务契约中,我定义了如下3个操作,他们的参数类型分别为IEnumerable<Customer>、IList<Cusomter>和Customer[]。当客户端通过添加服务引用导出服务契约后,3个操作的参数类型都变成Customer[]了。
1: [ServiceContract]
<!--CRLF-->
2: public interface ICustomerManager
<!--CRLF-->
3: {
<!--CRLF-->
4: [OperationContract]
<!--CRLF-->
5: void AddCustomerArray(Customer[] customers);
<!--CRLF-->
6: [OperationContract]
<!--CRLF-->
7: void AddCustomerCollection(IEnumerable<Customer> customers);
<!--CRLF-->
8: [OperationContract]
<!--CRLF-->
9: void AddCustomerList(IList<Customer> customers);
<!--CRLF-->
10: }
<!--CRLF-->
1: [ServiceContract]
<!--CRLF-->
2: [ServiceContract]
<!--CRLF-->
3: public interface ICustomerManager
<!--CRLF-->
4: {
<!--CRLF-->
5: [OperationContract]
<!--CRLF-->
6: void AddCustomerArray(Customer[] customers);
<!--CRLF-->
7: [OperationContract]
<!--CRLF-->
8: void AddCustomerCollection(Customer[] customers);
<!--CRLF-->
9: [OperationContract]
<!--CRLF-->
10: void AddCustomerList(Customer[] customers);
<!--CRLF-->
11: }
<!--CRLF-->
由于对于DataContractSerializer来说,IEnumerable<Customer>、IList<Cusomter>和Customer[]这3种形式的数据表述方式是等效的,那么就意味着当客户端在通过添加服务引用导入服务契约的时候,customers通过Customer[]与通过IList<Cusomter>表示也具有等效性,我们能否让数组类型变成IList<T>类型呢,毕竟从编程角度来看,它们还是不同的,很多时候使用IList<T>要比直接使用数组方便得多。
答案是肯定的,Vistual Studio允许我们在添加服务引用的时候进行一些定制,其中生成的集合类型和字典集合类型的定制就包含其中。如图1所示,VS为我们提供了6种不同的集合类型供我们选择:Array、ArrayList、LinkedList、GenericList、Collection、BindingList。
对于上面定义的服务契约ICustomerManager,如果在添加服务引用时使用GenericList选项,导入的服务契约的所有操作参数类型全部变成List<Customer>。
1: [ServiceContract]
<!--CRLF-->
2: public interface ICustomerManager
<!--CRLF-->
3: {
<!--CRLF-->
4: [OperationContract]
<!--CRLF-->
5: void AddCustomerArray(List<Customer> customers);
<!--CRLF-->
6: [OperationContract]
<!--CRLF-->
7: void AddCustomerCollection(List<Customer> customers);
<!--CRLF-->
8: [OperationContract]
<!--CRLF-->
9: void AddCustomerList(List<Customer> customers);
<!--CRLF-->
10: }
<!--CRLF-->
图1 在添加服务引用时指定集合类型
二、IEnumerable与IList
上面我们介绍了IEnumerable<T>、Array与IList<T>这3种集合类型的序列化规则,这3种集合类型有一个共同的特点,那就是集合类型的申明指明了集合元素的类型。当基于这3种集合类型的DataContractSerializer被创建出来后,由于元素类型已经明确了,所以能够按照元素类型对应的数据契约的定义进行合理的序列化工作。但是对于不能预先确定元素类型的IEnumerable和IList就不一样了。
下面我将演示IEnumerable和IList两种类型的序列化。在介绍已知类型的时候,我们已经明确了,无论是序列化还是反序列化都需要预先明确对象的真实类型,对于不能预先确定具体类型的情况下,我们需要潜在的类型添加到DataContractSerializer的已知类型列表中,才能保证序列化和反序列化的正常进行。由于创建基于IEnumerable和IList的DataContractSerializer的时候,集合元素类型是不可知的,所以需要将潜在的元素类型添加到DataContractSerializer的已知类型列表中,为此我们使用下面一个包含已知类型列表参数的Serialize<T>辅助方法进行序列化工作。
1: public static void Serialize<T>(T instance, string fileName, IList<Type> konwnTypes)
<!--CRLF-->
2: {
<!--CRLF-->
3: DataContractSerializer serializer = new DataContractSerializer(typeof(T), konwnTypes, int.MaxValue, false, false, null);
<!--CRLF-->
4: using (XmlWriter writer = new XmlTextWriter(fileName, Encoding.UTF8))
<!--CRLF-->
5: {
<!--CRLF-->
6: serializer.WriteObject(writer, instance);
<!--CRLF-->
7: }
<!--CRLF-->
i
分享到:
相关推荐
蒋金楠老师的wcf教程,个人看了,觉得写的很不错,对刚入门和深入了解wcf都适用,有需要的同学可下载学习
WCF服务的操作方法中实现T GetEntity(int id) where T: EntityBase
文档清楚明了的讲述如何在WCF的操作方法中达到泛型效果。
通过抽象工厂模式访问两种数据库 SQL 和Access 利用泛型读取表中数据 WCF发布出去
WCF技术剖析
WCF技术剖析(卷1),是一本非常专业的不错的WCF技术类的书籍。
对wcf中[DataContract]的描述
演示了WCF怎样进行序列化复杂类型,使用DATACONTRACT进行数据序列化。
WCF定义了四种契约类型: 1.服务契约(Service Contract):定义客户端能够执行的服务操作。 2.数据契约(Data Contract):定义于服务交互的数据类型。 3.错误契约(Fault Contract):定义抛出的错误。 ...
WCF数据契约实例源码;从最简单的步骤开始,一步一步学会契约的使用
WCF 元数据 查询器 WCF 元数据 分析器 WCF 元数据 查询器 WCF 元数据 分析器
WCF技术剖析 从基础开始:WCF简介,终结点地址和wcf寻址等
《WCF技术剖析》从WCF的终结点谈起,对终结点的三要素进行了全面而深入的介绍,帮助读者了解地址、绑定和契约的本质。 通过本书对序列化的深入讲解,读者可了解WCF进行操作方法调用与消息之间转化的本质;深入剖析...
比较早的WCF里使用EF的poco生成数据契约的小例子
(3):契约版本处理-WCF课件-《构建WCF面向服务的应用程序》
构建WCF面向服务的应用程序系列课程:WCF契约设计
蒋金楠 作品+原书加源码,非常适合学习,剩下你懂的。
主要包含了WCF学习中数据契约的实例完成代码,服务器,宿主,客户端结构清晰,对初学者有很好的帮助作用。
WCF 元数据浏览器 WCF 元数据浏览器