.net中物件序列化技術淺談

lingxyd_0發表於2013-01-07


序列化是將物件狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為物件。這兩個過程結合起來,可以輕鬆地儲存和傳輸資料。例如,可以序列化一個物件,然後使用 HTTP 通過 Internet 在客戶端和伺服器之間傳輸該物件。反之,反序列化根據流重新構造物件。此外還可以將物件序列化後儲存到本地,再次執行的時候可以從本地檔案中“恢復”物件到序列化之前的狀態。
在.net中有提供了幾種序列化的方式:
二進位制序列化
XML序列化
SOAP序列化

 

二進位制序列化
所謂二進位制序列化,指的是物件序列化之後是二進位制形式的。二進位制序列化是通過BinaryFormatter類來實現的,這個類位於System.Runtime.Serialization.Formatters.Binary名稱空間下。

XML序列化
所謂XML序列化,是指物件序列化之後的結果是XML形式的。儲存XML序列化是通過XmlSerializer 類來實現的, 這個類位於System.Xml.Serialization名稱空間下。

SOAP序列化
所謂SOAP序列化是指物件序列化之後的結果符合SOAP協議,也就是可以通過SOAP協議傳輸(不知道SOAP協議?百度一下吧)。SOAP序列化是通過SoapFormatter類來實現的,這個類位於System.Runtime.Serialization.Formatters.Soap名稱空間下,並且需要注意需要手動新增對這個名稱空間的引用,如下圖所示:
 

下面編寫一個類用於序列化和反序列化,這個類的程式碼如下:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace MySerializeDemo  
  6. {  
  7.     [Serializable]  
  8.     /// <summary>  
  9.     /// 要序列化的物件  
  10.     /// 作者:周公  
  11.     /// 編寫時間:2009-03-10  
  12.     /// </summary>  
  13.     public class MyObject  
  14.     {  
  15.         //[NonSerialized]  
  16.         private string name;  
  17.         private DateTime birthday;  
  18.         private string homePlace;  
  19.         /// <summary>  
  20.         /// 出生地  
  21.         /// </summary>  
  22.         public string HomePlace  
  23.         {  
  24.             get { return homePlace; }  
  25.             set { homePlace = value; }  
  26.         }  
  27.    
  28.         /// <summary>  
  29.         /// 生日  
  30.         /// </summary>  
  31.         public DateTime Birthday  
  32.         {  
  33.             get { return birthday; }  
  34.             set { birthday = value; }  
  35.         }  
  36.    
  37.         /// <summary>  
  38.         /// 姓名  
  39.         /// </summary>  
  40.         public string Name  
  41.         {  
  42.             get { return name; }  
  43.             set { name = value; }  
  44.         }  
  45.    
  46.         /// <summary>  
  47.         /// 年齡  
  48.         /// </summary>  
  49.         public int Age  
  50.         {  
  51.             get { return DateTime.Now.Year - birthday.Year; }  
  52.         }  
  53.         /// <summary>  
  54.         /// override了ToString()方法  
  55.         /// </summary>  
  56.         /// <returns></returns>  
  57.         public override string ToString()  
  58.         {  
  59.             return string.Format("姓名:{0},生日:{1},出生地:{2},年齡:{3}",name,birthday,homePlace,Age);  
  60.         }  
  61.    
  62.     }  
  63. }  

下面是分別用上面的三個類進行序列化和反序列化的程式碼:

[c-sharp] view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using System.IO;  
  5. using System.Runtime.Serialization.Formatters;  
  6. using System.Runtime.Serialization.Formatters.Binary;  
  7. using System.Runtime.Serialization.Formatters.Soap;  
  8. using System.Xml.Serialization;  
  9.   
  10. namespace MySerializeDemo  
  11. {  
  12.     class Program  
  13.     {  
  14.         static void Main(string[] args)  
  15.         {  
  16.             MyObject obj = new MyObject();  
  17.             obj.Birthday = new DateTime(1979, 11, 7);  
  18.             obj.HomePlace = "湖北";  
  19.             obj.Name = "周公";  
  20.             Console.WriteLine("========使用BinaryFormatter類進行序列化和反序列化。====");  
  21.             BinarySerialize(obj);  
  22.             BinaryDeserialize("C://MyObject.dat");  
  23.             Console.WriteLine("========使用SoapFormatter類進行序列化和反序列化。====");  
  24.             SOAPSerialize(obj);  
  25.             SOAPDeserialize("C://MyObject.soap");  
  26.             Console.WriteLine("========使用XmlSerializer類進行序列化和反序列化。====");  
  27.             XMLSerialize(obj);  
  28.             XMLDeserialize("C://MyObject.xml");  
  29.         }  
  30.         /// <summary>  
  31.         /// 二進位制序列化物件  
  32.         /// </summary>  
  33.         /// <param name="obj"></param>  
  34.         public static void BinarySerialize(MyObject obj)  
  35.         {  
  36.             using (FileStream stream = new FileStream("C://MyObject.dat", FileMode.Create, FileAccess.Write))  
  37.             {  
  38.                 BinaryFormatter formater = new BinaryFormatter();  
  39.                 formater.Serialize(stream, obj);  
  40.                 Console.WriteLine("物件已經被序列化。" + obj.ToString());  
  41.             }  
  42.         }  
  43.         /// <summary>  
  44.         /// 二進位制反序列化  
  45.         /// </summary>  
  46.         /// <param name="fileName"></param>  
  47.         public static void BinaryDeserialize(string fileName)  
  48.         {  
  49.             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))  
  50.             {  
  51.                 BinaryFormatter formater = new BinaryFormatter();  
  52.                 MyObject obj=(MyObject)formater.Deserialize(stream);  
  53.                 Console.WriteLine("物件已經被反序列化。" + obj.ToString());  
  54.             }  
  55.         }  
  56.   
  57.         /// <summary>  
  58.         /// 二進位制序列化物件  
  59.         /// </summary>  
  60.         /// <param name="obj"></param>  
  61.         public static void SOAPSerialize(MyObject obj)  
  62.         {  
  63.             using (FileStream stream = new FileStream("C://MyObject.soap", FileMode.Create, FileAccess.Write))  
  64.             {  
  65.                 SoapFormatter formater = new SoapFormatter();  
  66.                 formater.Serialize(stream, obj);  
  67.                 Console.WriteLine("物件已經被序列化。" + obj.ToString());  
  68.             }  
  69.         }  
  70.         /// <summary>  
  71.         /// 二進位制反序列化  
  72.         /// </summary>  
  73.         /// <param name="fileName"></param>  
  74.         public static void SOAPDeserialize(string fileName)  
  75.         {  
  76.             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))  
  77.             {  
  78.                 SoapFormatter formater = new SoapFormatter();  
  79.                 MyObject obj = (MyObject)formater.Deserialize(stream);  
  80.                 Console.WriteLine("物件已經被反序列化。" + obj.ToString());  
  81.             }  
  82.         }  
  83.         /// <summary>  
  84.         /// XML序列化  
  85.         /// </summary>  
  86.         /// <param name="obj"></param>  
  87.         public static void XMLSerialize(MyObject obj)  
  88.         {  
  89.             using (FileStream stream = new FileStream("C://MyObject.xml", FileMode.Create, FileAccess.Write))  
  90.             {  
  91.                 XmlSerializer serializer = new XmlSerializer(typeof(MyObject));  
  92.                 serializer.Serialize(stream, obj);  
  93.                 Console.WriteLine("物件已經被序列化。" + obj.ToString());  
  94.             }  
  95.         }  
  96.         /// <summary>  
  97.         /// XML反序列化  
  98.         /// </summary>  
  99.         /// <param name="fileName"></param>  
  100.         public static void XMLDeserialize(string fileName)  
  101.         {  
  102.             using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))  
  103.             {  
  104.                 XmlSerializer serializer = new XmlSerializer(typeof(MyObject));  
  105.                 MyObject obj = (MyObject)serializer.Deserialize(stream);  
  106.                 Console.WriteLine("物件已經被反序列化。" + obj.ToString());  
  107.             }  
  108.         }  
  109.     }  
  110. }  

這個程式的執行效果如下:
 
可見通過上面三個類都能實現將物件序列化儲存,並且都能反序列化還原到物件被序列化之前的狀態(這正是序列化意義所在,能儲存物件執行時的狀態並且還能還原)。如果執行上面的程式碼會在C盤根目錄下建立三個檔案,分別是MyObject.dat、MyObject.soap和MyObject.xml檔案,因為MyObject.dat是二進位制檔案,所以無法檢視檔案的內容,但是我們可以開啟MyObject.soap和MyObject.xml這兩個檔案來比較一下有什麼區別。
MyObject.soap檔案的字尾雖然是.soap,但是還是可以用記事本開啟的,下面是MyObject.soap檔案的內容:
[xhtml] view plaincopy
  1. <SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">  
  2. <SOAP-ENV:Body>  
  3. <a1:MyObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/MySerializeDemo/MySerializeDemo%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">  
  4. <name id="ref-3">周公</name>  
  5. <birthday>1979-11-07T00:00:00.0000000+08:00</birthday>  
  6. <homePlace id="ref-4">湖北</homePlace>  
  7. </a1:MyObject>  
  8. </SOAP-ENV:Body>  
  9. </SOAP-ENV:Envelope>  

MyObject.xml檔案也可以用記事本開啟,它的內容如下:

[xhtml] view plaincopy
  1. <?xml version="1.0"?>  
  2. <MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
  3.   <HomePlace>湖北</HomePlace>  
  4.   <Birthday>1979-11-07T00:00:00</Birthday>  
  5.   <Name>周公</Name>  
  6. </MyObject>  

熟悉SOAP協議的朋友一看MyObject.soap檔案的內容就知道它符合SOAP協議,MyObject.xml檔案毫無疑問是一個符合XML規範的檔案。

對程式碼作幾點說明:
1、如果採用BinaryFormatter類或者SoapFormatter類來實現序列化,則一定要給類加上Serializable屬性,如程式碼中所示:

[c-sharp] view plaincopy
  1. [Serializable]  
  2.     /// <summary>  
  3.     /// 要序列化的物件  
  4.     /// 作者:周公  
  5.     /// 編寫時間:2009-03-10  
  6.     /// </summary>  
  7.     public class MyObject  

如果不給要序列化的物件加上這個屬性,那麼採用採用BinaryFormatter類或者SoapFormatter類來實現序列化時會報異常,但使用XmlSerializer 類序列化物件時可以不用這個屬性。
2、另外,如果不想序列化某個欄位,可以給其加上NonSerialized屬性,這樣在序列化時就不會儲存這個這個欄位的值了,比如不想序列化name這個欄位,可以如下寫程式碼:

[c-sharp] view plaincopy
  1. //其它程式碼  
  2. //[NonSerialized]  
  3. private string name;  
  4. //其它程式碼  

再次執行剛才的程式會得到如下效果:
 
看有黃色底線部分,因為name欄位不被序列化,所以通過二進位制序列化和SOAP序列化之後再反序化就得不到原來的值了。
3、最後還需要說明一點的是,SoapFormatter類在.net3.5開始已經過時了,微軟建議使用BinaryFormatter類來序列化和反序列化了。



轉貼於: http://blog.csdn.net/zhoufoxcn/article/details/3978874



相關文章