標籤:
序列化是指將對象執行個體的狀態儲存到儲存媒體的過程,在此過程中,先將對象的公用欄位和私人欄位以及類的名稱(包括類所在的程式集)轉
換為位元組流,然後再把位元組流寫入資料流,在隨後對對象進行還原序列化時,將建立出與原對象完全相同的副本。
在物件導向的環境中實現序列化機制時,必須在易用性和靈活性之間進行一些權衡。只要您對此過程有足夠的控制能力,就可以使該過程在很大程度上自動進行。例如,簡單的二進位序列化不能滿足需要,或者,由於特定原因需要確定類中那些欄位需要序列化。以下各部分將探討 .NET 架構提供的可靠的序列化機制,並著重介紹使您可以根據需要自訂序列化過程的一些重要功能。
持久儲存 我們經常需要將對象的欄位值儲存到磁碟中,並在以後檢索此資料。儘管不使用序列化也能完成這項工作,但這種方法通常很繁瑣而且容易出錯,並且在需要跟蹤對象的階層時,會變得越來越複雜。可以想象一下編寫包含大量對象的大型商務應用程式的情形,程式員不得不為每一個對象編寫代碼,以便將欄位和屬性儲存至磁碟以及從磁碟還原這些欄位和屬性。序列化提供了輕鬆實現這個目標的快捷方法。
通用語言執行平台 (CLR) 管理對象在記憶體中的分布,.NET 架構則通過使用反射提供自動的序列化機制。對象序列化後,類的名稱、程式集以及類執行個體的所有資料成員均被寫入儲存媒體中。對象通常用成員變數來儲存對其他執行個體的引用。類序列化後,序列化引擎將跟蹤所有已序列化的引用對象,以確保同一對象不被序列化多次。.NET 架構所提供的序列化體繫結構可以自動正確處理對象圖表和循環參考。對對象圖表的唯一要求是,由進行中序列化的對象所引用的所有對象都必須標記為 Serializable(請參閱基本序列化)。否則,當序列化程式試圖序列化未標記的對象時將會出現異常。
當還原序列化已序列化的類時,將重新建立該類,並自動還原所有資料成員的值。
按值封送 對象僅在建立對象的應用程式定義域中有效。除非對象是從 MarshalByRefObject 派生得到或標記為 Serializable,否則,任何將對象作為參數傳遞或將其作為結果返回的嘗試都將失敗。如果對象標記為 Serializable,則該對象將被自動序列化,並從一個應用程式定義域傳輸至另一個應用程式定義域,然後進行還原序列化,從而在第二個應用程式定義域中產生出該對象的一個完全重複項。此過程通常稱為按值封送。
如果對象是從 MarshalByRefObject 派生得到,則從一個應用程式定義域傳遞至另一個應用程式定義域的是對象引用,而不是對象本身。也可以將從 MarshalByRefObject 派生得到的對象標記為 Serializable。遠程使用此對象時,負責進行序列化並已預先配置為 SurrogateSelector 的格式化程式將控制序列化過程,並用一個代理替換所有從 MarshalByRefObject 派生得到的對象。如果沒有預先配置為 SurrogateSelector,序列化體繫結構將遵從下面的標準序列化規則(請參閱序列化過程的步驟)。
基本序列化
要使一個類可序列化,最簡單的方法是使用 Serializable 屬性對它進行標記,如下所示:
[Serializable] public class MyObject { public int n1 = 0; public int n2 = 0; public String str = null; } 以下程式碼片段說明了如何將此類的一個執行個體序列化為一個檔案:
MyObject obj = new MyObject(); obj.n1 = 1; obj.n2 = 24; obj.str = "一些字串"; IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None); formatter.Serialize(stream, obj); stream.Close(); 本例使用二進位格式化程式進行序列化。您只需建立一個要使用的流和格式化程式的執行個體,然後調用格式化程式的 Serialize 方法。流和要序列化的對象執行個體作為參數提供給此調用。類中的所有成員變數(甚至標記為 private 的變數)都將被序列化,但這一點在本例中未明確體現出來。在這一點上,二進位序列化不同於只序列化公用欄位的 XML 序列化程式。
將對象還原到它以前的狀態也非常容易。首先,建立格式化程式和流以進行讀取,然後讓格式化程式對對象進行還原序列化。以下程式碼片段說明了如何進行此操作。
IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream("MyFile.bin", FileMode.Open,FileAccess.Read,FileShare.Read);
Myobject obj =(Myobject)formatter.Deserialize(stream);
stream.close()
Console.WriteLine("n1:{0}",obj.n1);
上面使用的BinaryFormatter效率很高,能產生非常緊湊的位元組流,所有使用此格式化程式序列化的對象也可以使用它進行還原序列化,對於序列化將在.net平台上進行還原序列化的對象,此格式化程式無疑是一個理想工具,需要注意的是:對對象進行還原序列化時並不調用建構函式,對還原序列化添加這項約束,是出於效能方面的考慮,但是,這違反了對象編寫者通常採用的一些運行時約定,因此,開發人員在將對象標記為
可序列化時,應確保考慮了這一特殊約定。
Serializable在C#中的作用.net中的對象序列化 (轉)