.NET 對象序列化

什麼是序列化?
  .net的運行時環境用來支持用戶定義類型的流化的機制。它是將對象實例的狀態存儲到存儲媒體的過程。在序列化的過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換爲字節流,然後再把字節流寫入數據流。在隨後對對象進行反序列化時,將創建出與原對象完全相同的副本。
序列化可以給我們帶來什麼樣的方便之處呢?
        1.持久存儲
       有時我們經常需要將對象的字段值保存到磁盤中,以便在以後檢索此數據。雖然沒有序列化也可以完成這項工作,但其方法往往是很繁瑣而且容易出錯的,並且在需要跟蹤對象的層次結構時,會變得越來越麻煩。我們可以想 象一下編寫包含大量對象的大型業務應用程序的情形,程序員不得不爲每一個對象編寫代碼,以便將字段和屬性保存至磁盤或從磁盤還原這些字段和屬性。不過序列化就不一樣了,它提供了輕鬆實現這個目標的快捷方法。
        公共語言運行時(CLR)管理對象在內存中的分佈,.NET框架則通過使用反射提供自動的序列化機制。對象被序列化後,類的名稱、程序集以及類實例的所有數據成員均被寫入存儲媒體中。對象通常用成員變量來存儲對其他實例的引用。類序列化後,序列化引擎將跟蹤所有已序列的引用對象,這樣就確保了同一對象不被序列化多次。.NET框架所提供的序列化體系結構可以自動正確處理對象圖表和循環引用。對對象圖表的唯一要求是,由正在進行序列化的對象所引用的所有對象都必須標記爲Serializable。否則序列化程序試圖序列化未標記的對象時將爲出現異常。Serializable屬性用來明確表示該類可以被序列化。同樣的,我們可以用NonSerializable屬性用來明確表示類不能被序列化。
這樣反序列化已序列化的類時,將重新創建該類,並還原所有數據成員的值。
        2.按值封送
       對象僅在創建對象的應用程序域中有效。除非對象是從MarshalByRefObject派生得到或標記爲Serializable,否則,任何將對象作爲參數傳遞或將其作爲結果返回的嘗試都將失敗。如果對象標記爲 Serializable,則該對象將被自動序列化,並從一個應用程序域傳輸至另一個應用程序域,然後進行反序列化,從而在第二個應用程序域中產生出該對象的一個精確副本。此過程通常稱爲按值封送。
序列化的實現
        序列化的機制是將類的值轉化爲一般的字節流,然後把這個流存儲到存儲媒介上。.NET框架裏提供了這樣兩個類 BinaryFormatter和SoapFormatter。BinaryFormatter使用二進制格式化程序進行序列化。它將類中的所有成員變量(甚至標記爲 private 的變量)都序列化。而SoapFormatter使用XML格式化,因此會有更好的可移植性。
下面是BinaryFormatter序列化和反序列化
 

基本序列化
        要使一個類可序列化,最簡單的方法是使用 Serializable 屬性對它進行標記,如下所示:

[Serializable]
public class ObjectSerializable
{
    
public int s1 = 0;
    
public int s2 = 0;
    
public String str = null;
}


        以下的方法說明了如何將此類的一個實例序列化爲一個文件?

    private void Serializable()
    
{
        ObjectSerializable MyObject 
= new ObjectSerializable();
        MyObject.s1 
= 1;
        MyObject.s2 
= 24;
        MyObject.str 
= "一些字符串";
        IFormatter Formatter 
= new BinaryFormatter();
        Stream stream 
= new FileStream(Server.MapPath("MyFile.bin"),FileMode.Create,FileAccess.Write,FileShare.None);
        Formatter.Serialize(stream,MyObject);
        stream.Close();

    }


        上面的方法創建一個要使用的流和格式化程序的實例,然後調用格式化程序的 Serialize 方法。流和要序列化的對象實例作爲參數提供給此調用。類中的所有成員變量(甚至標記爲 private 的變量)都將被序列化,但這一點在本例中未明確體現出來。在這一點上,二進制序列化不同於只序列化公共字段的 XML 序列化程序。

        將對象還原到它以前的狀態也非常容易。首先,創建格式化程序和流以進行讀取,然後讓格式化程序對對象進行反序列化。以下代碼片段說明了如何進行此操作。

   private void ReadSerializable()
    
{
        IFormatter Formatter 
= new BinaryFormatter();
        Stream stream 
= new FileStream(Server.MapPath("MyFile.bin"),FileMode.Open,FileAccess.Read,FileShare.Read);
        ObjectSerializable MyObject 
= (ObjectSerializable)Formatter.Deserialize(stream);
        stream.Close();
        Console.WriteLine(
"s1: {0}", MyObject.s1);
        Console.WriteLine(
"s2: {0}", MyObject.s2);
        Console.WriteLine(
"str: {0}", MyObject.str);
    }


        BinaryFormatter 效率很高,能生成非常緊湊的字節流。所有使用此格式化程序序列化的對象也可使用它進行反序列化,對於序列化將在 .NET 平臺上進行反序列化的對象。
        如果你想具有可移植性,請使用 SoapFormatter。所要做的更改只是將以上代碼中的格式化程序換成SoapFormatter,而 Serialize 和 Deserialize 調用不變。對於上面使用的示例,該格式化程序將生成以下結果。

 <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/">
    
<SOAP-ENV:Body>
       
<a1:ObjectSerializable id="ref-1" 
                xmlns:a1
="http://schemas.microsoft.com/clr/assem/App_Web_9qmp6o-m%2C%20Version%3D0.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull">
              
<s1>1</n1> 
              
<s2>24</n2> 
              
<str id="ref-3">一些字符串</str> 
          
</a1:ObjectSerializable>
      
</SOAP-ENV:Body>
  
</SOAP-ENV:Envelope>


需要注意的是,Serializable 屬性是無法繼承的。如果從 MyObject 派生出一個新的類,則這個新的類也必須使用該屬性進行標記,否則將無法序列化。例如,如果試圖序列化以下類實例,將會顯示一個 SerializationException,說明 MyStuff 類型未標記爲可序列化。

public class MyStuff : ObjectSerializable
{
    
public int str1 = null;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章