[C# 基礎知識系列]專題三:C#中爲什麼序列化,如何序列化?
提到爲了傳遞數據,需要把作爲載體的實體類序列化,好好的找了一些序列化方面的介紹。感覺下面的這個介紹比較容易介紹!
1.什麼是序列化
序列化是將對象狀態轉換爲可保持或傳輸的格式的過程,在序列化過程中,對象的公共字段和私有字段以及類的名稱(包括包含該類的程序集)都被轉換爲字節流,然後寫入數據流。與序列化相對的是反序列化,它將流轉換爲對象。這兩個過程結合起來,可以輕鬆地存儲和傳輸數據。
2.爲什麼使用序列化
a. 一個原因是將對象的狀態保持在存儲媒體中,以便可以在以後重新創建精確的副本。
我們經常需要將對象的字段值保存到磁盤中,並在以後檢索此數據。儘管不使用序列化也能完成這項工作,但這種方法通常很繁瑣而且容易出錯,並且在需要跟蹤對象的層次結構時,會變得越來越複雜。可以想象一下編寫包含大量對象的大型業務應用程序的情形,程序員不得不爲每一個對象編寫代碼,以便將字段和屬性保存至磁盤以及從磁盤還原這些字段和屬性。序列化提供了輕鬆實現這個目標的快捷方法。
b.另一個原因是通過值將對象從一個應用程序域發送到另一個應用程序域中。
例如,序列化可用於在 ASP.NET 中保存會話狀態並將對象複製到 Windows 窗體的剪貼板中。遠程處理還可以使用序列化通過值將對象從一個應用程序域傳遞到另一個應用程序域中。
公共語言運行時 (CLR) 管理對象在內存中的分佈,.NET 框架則通過使用反射提供自動的序列化機制。對象序列化後,類的名稱、程序集以及類實例的所有數據成員均被寫入存儲媒體中。對象通常用成員變量來存儲對其他實例的引用。類序列化後,序列化引擎將跟蹤所有已序列化的引用對象,以確保同一對象不被序列化多次。.NET
框架所提供的序列化體系結構可以自動正確處理對象圖表和循環引用。對對象圖表的唯一要求是,由正在進行序列化的對象所引用的所有對象都必須標記爲 Serializable(請參閱基本序列化)。否則,當序列化程序試圖序列化未標記的對象時將會出現異常。
當反序列化已序列化的類時,將重新創建該類,並自動還原所有數據成員的值。
3.如何實現對象的序列化及反序列化
要實現對象的序列化,首先要保證該對象可以序列化。而且,序列化只是將對象的屬性進行有效的保存,對於對象的一些方法則無法實現序列化的。
實現一個類可序列化的最簡便的方法就是增加Serializable屬性標記類。如:
[Serializable()]
public class MEABlock
{
private int m_ID;
public string Caption;
public MEABlock()
{
///構造函數
}
}
即可實現該類的可序列化。注意序列化的類必須爲Public,否則不能夠被序列化。
要將該類的實例序列化爲到文件中?.NET FrameWork提供了兩種方法:
a
.XML序列化
使用 XmLSerializer 類,可將下列項序列化。
公共類的公共讀/寫屬性和字段
實現 ICollection 或 IEnumerable 的類。(注意只有集合會被序列化,而公共屬性卻不會。)
XmlElement 對象。
XmlNode 對象。
DataSet 對象。
要實現上述類的實例的序列化,可參照如下例子:
MEABlock myBlock = new MEABlock();
// Insert code to set properties and fields of the object.
XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
// To write to a file, create a StreamWriter object.
StreamWriter myWriter = new StreamWriter("myFileName.xml");
mySerializer.Serialize(myWriter, MEABlock);
需要注意的是XML序列化只會將public的字段保存,對於私有字段不予於保存。
生成的XML文件格式如下:
<MEABlock>
<Caption>Test</Caption>
</MEABlock>
對於對象的反序列化,則如下:
MEABlock myBlock;
// Constructs an instance of the XmlSerializer with the type
// of object that is being deserialized.
XmlSerializer mySerializer = new XmlSerializer(typeof(MEABlock));
// To read the file, creates a FileStream.
FileStream myFileStream = new FileStream("myFileName.xml", FileMode.Open);
// Calls the Deserialize method and casts to the object type.
myBlock = (MEABlock)mySerializer.Deserialize(myFileStream)
b.
二進制序列化
與XML序列化不同的是,二進制序列化可以將類的實例中所有字段(包括私有和公有)都進行序列化操作。這就更方便、更準確的還原了對象的副本。
要實現上述類的實例的序列化,可參照如下例子:
MEABlock myBlock = new MEABlock();
// Insert code to set properties and fields of the object.
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin",FileMode.Create,FileAccess.Write, FileShare.None);
formatter.Serialize(stream, myBlock);
stream.Close();
對於對象的反序列化,則如下:
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Open,FileAccess.Read, FileShare.Read);
MEABlock myBlock = (MEABlock) formatter.Deserialize(stream);
stream.Close();
4、如何變相實現自定義可視化控件的序列化、反序列化
對於WinForm中自定義控件,由於繼承於System.Windows.Form類,而Form類又是從MarshalByRefObject繼承的,窗體本身無法做到序列化,窗體的實現基於Win32下GUI資源,不能脫離當前上下文存在。
當然可以採用變通的方法實現控件的序列化。這裏採用的是記憶類模型。
定義記憶類(其實就是一個可序列化的實體類)用於記錄控件的有效屬性,需要序列化控件的時候,只需要將該控件的實例Copy到記憶類,演變成序列化保存該記憶類的操作。
反序列化是一個逆過程。將數據流反序列化成爲該記憶類,再根據該記憶類的屬性生成控件實例。而對於控件的一些事件、方法則可以繼續使用。
wwf之所以強調要把類實例化,就是因爲工作流和應用程序是在不同的線程中。二者之間需要用類作爲傳遞數據的載體的話,就需要把該類定義爲public序列化爲二進制傳輸。