序列化定義 序列化是將對象狀態轉換爲可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換爲對象。在此過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換爲字節流,然後再把字節流寫入數據流。在隨後對對象進行反序列化時,將創建出與原對象完全相同的副本。
序列化種類 .NET框架提供兩種格式的序列化,二進制序列化(Binary Serialization)和XML序列化(XML Serialization)。
1. 二進制序列化:將對象分解成爲簡單的二進制格式,這種類型的序列化並不會遺失原來的類型數據,對象使用二進制序列化分解之後,可以被傳送至各種存儲媒介,包括數據流,磁盤,內存甚至網絡上連接的主機。 2. XML序列化:將對象分解成爲XML格式,使用SOAP標準來訪問,由於XML與SOAP是開放標準,因此特別適用於對象需要跨越網絡傳送的情形,與二進制序列化不同的是,使用這種格式的序列化,只會序列化分解類型中的公用(Public)屬性和字段等內容。
序列化類的功能 .NET框架針對兩種不同格式的序列化技術,均提供了相應的類:BinaryFormatter類以及SoapFormatter ,XmlSerializer類。
BinaryFormatter用於二進制格式序列化的操作,位於如下命名空間中: System.Runtime.Serialization.Formatters.Binary
SoapFormatter提供XML序列化的支持,其所處的命名空間如下: System.Runtime.Serialization.Formatters.Soap
XmlSerializer提供XML序列化支持,所處命名空間爲: System.Xml.Serialization
這三種類提供對象序列化分解操作以及還原序列化的相關方法,簡化序列化對象所需的實現細節。而要想實際的寫出這個流,就要使用那些實現了IFormatter接口的類裏的Serialize和Deserialize方法。
1.BinaryFormatter類用來將對象進行二進制的格式化分解,並將二進制格式化分解的對象組合還原,Serialize() 以及Deserialize() 方法分別用來序列化以及還原序列化。下面是Serialize() 方法的定義: Public void Serialize(Stream,object);此方法接受stream類型以及object類型對象參數,將其中object類型對象序列化之後,傳遞到第1個參數所指定的數據流對象。下面是還原序列化的方法Deserialize() 的定義,這個方法將上面序列化分解的對象重新組合還原,以取得原始對象: Public object Deserialize(Stream serializationStream);其中Stream類型參數便是所要還原的數據流,Deserialize方法從這個數據流對象中重新組合還原被序列化分解的對象。
2.SoapFormatter類用來將對象序列化分解爲SOAP格式以及還原序列化對象,這個類同樣提供序列化對象以及還原序列化操作的方法,名稱同樣爲Serialize() 以及Deserializ() ,甚至所接受的參數值與上面的BinaryFormatter類也相同。
當要將一個類的實例對象進行序列化分解之前,首先必須要確認這個類是否可以進行序列化分解,一個類通常通過屬性 [Serializable] 將其標註爲可序列化(XmlSerializer方法可以不標註而直接序列化),換句話說,可以依據所要序列化分解的格式,使用上面任一個類對標註爲 [Serializable] 的類實例對象進行序列化分解。當然,在序列化對象時,也可以使用屬性 [NonSerialized] ,將對象中的某些成員標註爲不可序列化,有選擇性的只分解對象中的某些數據成員,那些標註爲 [NonSerialized] 的數據成員,在對象的序列化過程中將不會被分解。
3. XmlSerializer類用來將對象序列化分解爲XML格式以及還原序列化對象,實現方法同上。
XmlSerializer支持很多特性(ATTRIBUTES),它們可以用於爲特定的類設定序列化方式。例如,可將某個字段或屬性標以 [XmlIgnore] 特性,從而將其排除在序列化機制之外。另外 [XmlElement] 可用於指定XML元素名稱(這個元素名稱被用於特定的屬性或字段)。
對於經由SoapFormatter,BinaryFormatter的序列化,也可以使用特性進行某種程度的控制。例如,[NonSerialized] 特性等價於XmlSerializer的 [XmlIgnore] 特性。對序列化過程的終極控制,可以通過在其實休打算被序列化的類上,實現ISerializable接口。XmlSerializer不能用於序列化任何實現了IDictionary接口的類的實體,比方說Hashtable(散列表),而SoapFormatter和BinaryFormatter卻沒有這個限制。
微軟將XmlSerializer用於Web Services,而將BinaryFormatter和SoapFormatter用於遠程化。
序列化類使用選擇 可以依據具體情況來進行有效。XmlSerializer的限制比較嚴格,比如,要求目標類有一個無參數的構造器,並且只有公開的讀,寫屬性和字段時纔可被序列化。不過,從好的方面說,XmlSerializer對定製XML文檔提供了良好的支持。XmlSerializer的特性意味着,它最適合用在跨平臺的情況下,或者用於從現有的XML文檔構建對象。SoapFormatter和BinaryFormatter比XmlSerializer的限制要少,它們可以序列化私有字段。然而,它們都需要目標類標以 [Serializable] 特性,因此,像XmlSerializer一樣,需要小心以序列化方式來編寫類。有些詭異的東西也是要小心提防的。在反序列化時,新對象的構造器並不被調用。對SoapFormatter和BinaryFormatter的選擇,取決於應用。BinaryFormatter對於序列化和反序列化都是發生在.NET平臺上並且執行性能很重要的情況大有用處。通常來說,在所有其它情況下,SoapFormatter更有意義,也更易於調試。
自定義序列化自定義序列化行爲 序列化與還原序列化均由指定的Formetter自動完成。也可以選擇實現ISerializable接口,自行創建專屬的Formetter,以達到自行控制對象序列化及還原序列化的目的。在某些情形下,我們特別需要序列化的過程,例如若變量值的內容在序列化之後會失去原先存儲的值,此時你便可以自定義序列化的行爲,強迫恢復原先的內容。你可以在對象序列化的過程中,進一步使用加密技術,改變數據的格式,在反序列化操作的時候,以相對的解密技術將數據還原。自定義序列化的行爲允許你設計序列化對象的過程,而不是直接將指定的對象分解然後放入網絡或是存儲到數據流,避免數據的遺失,甚至在序列化進程發生不當擷取的情形。 自定義序列化方法實現ISerializable接口可以幫助你自定義對象的序列化行爲,繼承這個接口的類,必須同時實現方法GetObjectData() 和Constructor構造函數。
GetObjectData() 用來將對象相關信息填入SerializationInfo對象,其定義如下: Void GetObjectData(SerializationInfo info,StreamingContext context);其中的info是SerializationInfo類型的對象參數。SerializationInfo類被設計用來存儲對象自定義序列化操作時所需的信息,context是一種StreamingContext結構類型參數,表示序列化操作的來源數據流。
除了實現GetObjectData() 方法外,自定義序列化的過程,還必須完成特定構造函數的實現,構造函數在對象還原序列化時,將上面的info 參數內容傳遞到類。實現構造函數,必須引用SerializationInfo所定義的實例方法GetValue() ,提供指定的成員變量值。其特定構造函數形式如下: Public 類名(SerializationInfo info,StreamingContext context);
ISerializable接口位於System.Runtime.Serialization命名空間,在實現接口之前,必須引用這個命名空間。
序列化屬性的繼承 對象的序列化屬性沒有辦法被繼承,換句話說,繼承標註爲 [Serialized] 類的子類,由其創建的實例對象,並沒有辦法被序列化,除非你明確地將其標註爲[Serialized],如果基類同時亦實現接口ISerializable,派生的子類同樣也必須實現方法GetObjectData() 以及構造函數,才能夠自定義序列化成員變量的相關程序。另外在還原序列化重組對象時所調用的構造函數,同樣必須繼承基類。
序列化數據的修正 當一個成員變量被標註爲 [NonSerialized] 時,由於在對象序列化的過程中,成員變量並沒有被分解,當進行還原序列化操作,即重組對象的時候,所得到的將不是原先的成員變量的值。如果想要改變這種預設行爲,可以在設計類的時候,繼承IDeserializationCallback接口,實現方法OnDeserialization() ,還原正確的數據值。
方法OnDeserialization() 的定義如下: Void OnDeserialization(object sender);
繼承IDeserializationCallback接口的類對象,在還原序列化的時候,會先調用OnDeserialization() 方法,執行其中的方法。
當我們操作一個包含大量的暫時性數據對象,而此時序列化對象的時候,會同時分解這些暫時性數據,連同分解後的對象一併寫入文件,可以想象,這種作法非但沒有意義,而且浪費資源。這時可以選擇先把這些數據成員標註爲 [NonSerialized] ,然後在還原序列化,重組對象的同時,調用方法OnDeserialization() ,還原先前未被序列化分解的成員變量,這樣一來,除了序列化的過程比較有效率外,還能夠兼顧數據的正確性。
序列化示例 序列化操作時需要引用的命名空間
using System.Runtime.Serialization; //包含可用於序列化和反序列化對象的類
using System.Runtime.Serialization.Formatters.Binary; //二進制序列化需要的命名空間
using System.Runtime.Serialization.Formatters.Soap; //Soap序列化需要的命名空間
using System.Xml.Serialization; //XML序列化需要的命名空間
|
BinaryFormatter方法
/* 定義一個簡單的測試類,用來測試Binary和Soap方式序列化和反序列化 */
[Serializable] /* 定義類MText屬性爲可序列化類 */
public class MText
{
public string str;
}
|
/* BinarySerialize方法將執行二進制序列化操作 */
public void BinarySerialize(MText mtx)
{
/* 創建文件流fs,並定義保存文件BinarySeri.txt */
FileStream fs = new FileStream("BinarySeri.txt", FileMode.Create);
/* 實例化二進制序列化操作類BinaryFormatter */
BinaryFormatter bf = new BinaryFormatter();
/* 調用Serialize方法進行二進制序列化操作,並將mtx的可序列化成員內容寫進文件流fs 中進行存放 */
bf.Serialize(fs, mtx);
/* 關閉文件流 */
fs.Close();
}
/* BinaryDeSerialize方法將執行二進制反序列化操作,並返回序列化類MText */
public MText BinaryDeSerialize()
{
/* 定義並實例化MText類,用來保存反序列化得到的結果 */
MText mtx = new MText();
/* 創建文件流fs,並定義讀取文件BinarySeri.txt */
FileStream fs = new FileStream("BinarySeri.txt", FileMode.Open);
/* 實例化二進制序列化操作類BinaryFormatter */
BinaryFormatter bf = new BinaryFormatter();
/* 調用Deserialize方法進行二進制反序列化操作,並將轉換後的結果賦給MText
變量mtx */
mtx = (MText)bf.Deserialize(fs);
/* 關閉文件流並反回結果 */
fs.Close();
return mtx;
}
|
SoapFormatter方法
XmlSerialize方法
方法詳見二進制序列化。
ISerializable方法
自定義序列化類由任何可進行序列化操作的方法進行直接使用。
Inherit(繼承)方法
繼承序列化類由任何可進行序列化操作的方法進行直接使用。
IDeserializationCallback方法