DataContractSerializer 類
使用提供的數據協定,將類型實例序列化和反序列化為 XML 流或文檔。 無法繼承此類。
命名空間: System.Runtime.Serialization
程序集: System.Runtime.Serialization(在 System.Runtime.Serialization.dll 中)
備注
使用 DataContractSerializer 類可以將類型實例序列化和反序列化為 XML 流或文檔。 通過將 DataContractAttribute 特性應用於類,而將DataMemberAttribute 特性應用於類成員,可以指定要序列化的屬性和字段。
從字面意思來理解就是:數據契約序列化,本文主要是講解用DataContractSerializer 序列化和反序列化,關於它在WCF中的應用大家可以參考《WCF全面解析上冊 蔣金楠著》第五章 序列化,里面有專門的介紹。
DataContractAttribute與DataMenmberAttribute
1 #region 程序集 System.Runtime.Serialization.dll, v4.0.0.0 2 // C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Runtime.Serialization.dll 3 #endregion 4 5 using System; 6 7 namespace System.Runtime.Serialization 8 { 9 // 摘要: 10 // 指定該類型要定義或實現一個數據協定,並可由序列化程序(如 System.Runtime.Serialization.DataContractSerializer)進行序列化。 11 // 若要使其類型可序列化,類型作者必須為其類型定義數據協定。 12 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)] 13 public sealed class DataContractAttribute : Attribute 14 { 15 // 摘要: 16 // 初始化 System.Runtime.Serialization.DataContractAttribute 類的新實例。 17 public DataContractAttribute(); 18 19 // 摘要: 20 // 獲取或設置一個值,該值指示是否保留對象引用數據。 21 // 22 // 返回結果: 23 // 如果使用標准 XML 保留對象引用數據,則為 true;否則為 false。 默認值為 false。 24 public bool IsReference { get; set; } 25 // 26 // 摘要: 27 // 獲取或設置類型的數據協定的名稱。 28 // 29 // 返回結果: 30 // 數據協定的本地名稱。 默認值是應用了該屬性的類的名稱。 31 public string Name { get; set; } 32 // 33 // 摘要: 34 // 獲取或設置類型的數據協定的命名空間。 35 // 36 // 返回結果: 37 // 協定的命名空間。 38 public string Namespace { get; set; } 39 } 40 }
從應用在DataContractAttribute上的AttributeUsageAttribute特性看,該特性只能用於枚舉、類、結構體而不能應用於接口,從關鍵字sealed知道DataContractAttribute是不可被繼承的。AllowMutiple屬性為False,表明一個數據類型上只能應用一個DataContractAttribute特性。
從上面對DataContractAttribute定義看出DataContractAttribute僅僅包含3個屬性成員,其中Name和Namespace表示數據契約的名稱和命名空間,IsReference表示在進行序列化的時候是否保持對象現有的引用結構,該屬性默認值為False。
數據契約成員采用顯示選擇機制,也就是說,應用了DataContractAttribute特性的數據類型的屬性/字段不會自動生成契約的數據成員,而只有那些應用了DataMemberAttribute特性的屬性/字段才屬於數據契約的成員。
1 #region 程序集 System.Runtime.Serialization.dll, v4.0.0.0 2 // C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Runtime.Serialization.dll 3 #endregion 4 5 using System; 6 7 namespace System.Runtime.Serialization 8 { 9 // 摘要: 10 // 當應用於類型的成員時,指定該成員是數據協定的一部分並可由 System.Runtime.Serialization.DataContractSerializer 11 // 進行序列化。 12 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)] 13 public sealed class DataMemberAttribute : Attribute 14 { 15 // 摘要: 16 // 初始化 System.Runtime.Serialization.DataMemberAttribute 類的新實例。 17 public DataMemberAttribute(); 18 19 // 摘要: 20 // 獲取或設置一個值,該值指定是否對正在被序列化的字段或屬性的默認值進行序列化。 21 // 22 // 返回結果: 23 // 如果應該在序列化流中生成成員的默認值,則為 true;否則為 false。 默認值為 true。 24 public bool EmitDefaultValue { get; set; } 25 // 26 // 摘要: 27 // 獲取或設置一個值,該值用於指示序列化引擎在讀取或反序列化時成員必須存在。 28 // 29 // 返回結果: 30 // 如果該成員是必需的,則為 true;否則為 false。 31 // 32 // 異常: 33 // System.Runtime.Serialization.SerializationException: 34 // 該成員不存在。 35 public bool IsRequired { get; set; } 36 // 37 // 摘要: 38 // 獲取或設置數據成員名稱。 39 // 40 // 返回結果: 41 // 該數據成員的名稱。 默認值是應用該屬性的目標的名稱。 42 public string Name { get; set; } 43 // 44 // 摘要: 45 // 獲取或設置成員的序列化和反序列化的順序。 46 // 47 // 返回結果: 48 // 序列化或反序列化的數字順序。 49 public int Order { get; set; } 50 } 51 }
從上面應用在DataMemberAttribute上的AttributeUsageAttribute特性來看,該特性只能應用在字段和屬性上。因為只有這兩種元素才是“數據”成員。4個屬性分別表示如下的含義。
- Name:數據成員的名稱,默認為字段或屬性的名稱。
- Order:相應的數據成員在最終序列化的XML中出現的位置,Order值越小越考前,默認值為-1.
- IsRequired:表明屬性成員是否是必須的成員。默認值為false,表明該成員是可以缺省的。
- EmitDefaultValue :獲取或設置一個值,該值指定是否對正在被序列化的字段或屬性的默認值進行序列化。如果應該在序列化流中生成成員的默認值,則為 true;否則為 false。 默認值為 true。
實例:
Person類
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Runtime.Serialization; 7 namespace DataContractSerializerDemo 8 { 9 [DataContract] 10 public class Person 11 { 12 public Person(string name, int age, DateTime bithday) 13 { 14 this.name = name; 15 this.age = age; 16 this.birthday = bithday; 17 } 18 private string name; 19 [DataMember] 20 public string Name 21 { 22 get { return name; } 23 set { name = value; } 24 } 25 private int age; 26 [DataMember] 27 public int Age 28 { 29 get { return age; } 30 set { age = value; } 31 } 32 private DateTime birthday; 33 [DataMember] 34 public DateTime Birthday 35 { 36 get { return birthday; } 37 set { birthday = value; } 38 } 39 } 40 }
Women類(Person類的子類)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Runtime.Serialization; 7 namespace DataContractSerializerDemo 8 { 9 [DataContract] 10 public class Women : Person 11 { 12 public Women(string name, int age, DateTime birthday, string bwh, string bra) 13 : base(name, age, birthday) 14 { 15 BWH = bwh; 16 Bra = bra; 17 } 18 /// <summary> 19 /// 罩杯 20 /// </summary> 21 [DataMember] 22 public string BWH { get; set; } 23 /// <summary> 24 /// 罩顏色 25 /// </summary> 26 public string Bra { get; set; } 27 } 28 }
控制台程序:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Runtime.Serialization; 7 using System.Xml; 8 namespace DataContractSerializerDemo 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 Person p = new Person("wolfy", 24, Convert.ToDateTime("1989-04-11")); 15 Women w = new Women("蒼老師",40,Convert.ToDateTime("1960-01-01"),"D罩杯","黑色蕾絲"); 16 Serialize<Person>(p, "p.xml"); 17 Serialize<Women>(w,"w.xml"); 18 Console.Read(); 19 20 } 21 /// <summary> 22 /// 序列化輔助方法 23 /// </summary> 24 /// <typeparam name="T"></typeparam> 25 /// <param name="instance"></param> 26 /// <param name="fileName"></param> 27 static void Serialize<T>(T instance, string fileName) 28 { 29 DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 30 using (XmlWriter writer = new XmlTextWriter(fileName,Encoding.UTF8)) 31 { 32 serializer.WriteObject(writer, instance); 33 } 34 } 35 } 36 }
最后生成的xml文件:p.xml
1 <Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataContractSerializerDemo"><Age>24</Age><Birthday>1989-04-11T00:00:00</Birthday><Name>wolfy</Name></Person>
w.xml
1 <Women xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/DataContractSerializerDemo"><Age>40</Age><Birthday>1960-01-01T00:00:00</Birthday><Name>蒼老師</Name><BWH>D罩杯</BWH></Women>
將數據契約與最終生成的XML結構進行對比,我們可以看出DataContractSerializer在默認的情況下采用了如下的序列化規則。
- XML的根節點名稱為數據契約類型的名稱(這里為Person),默認的命名空間采用的格式為 http://schemas.datacontract.org/2004/07/DataContractSerializerDemo(數據契約類型的命名空間)。
- 只有顯示地應用了DataMemberAttributue特性的字段或屬性才能作為數據成員參與序列化。
- 所有數據成員均以XML元素的形式被序列化。
- 序列化后數據成員在XML中的次序采用這樣的規則:父類數據成員在前,子類數據成員在后;定義在同一個類型中的數據成員按照字母排序。
如果默認序列化后的xml結構不能滿足我們的需求,則可以通過DataContractAttribute和DataMenmberAttribute這兩個特性對其進行修正。在下面我們通過DataContractAttribute特性設置了數據契約的名稱和命名空間,通過DataMenmberAttribute特性的Name屬性為Name和Birthday兩個屬性設置不同於屬性名稱的數據成員名稱,並通過Order控制數據成員的先后次序。
修改后的Person類為:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Runtime.Serialization; 7 namespace DataContractSerializerDemo 8 { 9 [DataContract(Namespace="http://www.wolfy.com/")] 10 public class Person 11 { 12 public Person(string name, int age, DateTime bithday) 13 { 14 this.name = name; 15 this.age = age; 16 this.birthday = bithday; 17 } 18 private string name; 19 [DataMember(Name="FirstName",Order=3)] 20 public string Name 21 { 22 get { return name; } 23 set { name = value; } 24 } 25 private int age; 26 [DataMember] 27 public int Age 28 { 29 get { return age; } 30 set { age = value; } 31 } 32 private DateTime birthday; 33 [DataMember(Name="生日",Order=1)] 34 public DateTime Birthday 35 { 36 get { return birthday; } 37 set { birthday = value; } 38 } 39 } 40 }
再次運行程序,得到如下一個表示序列化的Person對象的XML結構:
<Person xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.wolfy.com/"><Age>24</Age><生日>1989-04-11T00:00:00</生日><FirstName>wolfy</FirstName></Person>
有關序列化的方方面面還有很多,這里就把經常用到介紹到這里。
反序列化輔助方法:
1 static T DeSerialize<T>(string fileName) 2 { 3 DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 4 using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 5 { 6 using (XmlReader reader = new XmlTextReader(fileName, fs)) 7 { 8 return (T)serializer.ReadObject(reader); 9 } 10 } 11 12 }
運行結果為:

從反序列化的結果也從側面印證了:只有顯示地應用了DataMemberAttributue特性的字段或屬性才能作為數據成員參與序列化。這條規則,因為在上面並沒有給bra這個屬性加DataMenmberAttribute這個特性,在生成的xml文件中沒有這個元素。反序列化也不會出現這個。
上篇隨筆: 序列化和反序列化的幾種方式(JavaScriptSerializer 、XmlSerializer、DataContractSerializer)(一)
參考文獻:
MSDN:http://msdn.microsoft.com/library/system.runtime.serialization.datacontractserializer.aspx
《WCF全面解析 上》 蔣金楠 著
