DotNet 序列化學習筆記

DotNet中的序列化方法有三種:XML 序列化、SOAP 序列化和二進制序列化。若是序列化到文件的話,前兩者生成的是 XML 文件,二進制序列化生成二進制文件。 

    跟序列化相關的兩個類型: 
    SerializableAttribute:指示一個類是可以序列化的。 
    ISerializable:使對象可以自己控制其序列化和反序列化的過程。 

    列表比較三種序列化方法。 

  XML SOAP 二進制
序列化器類 XmlSerializer SoapFormatter BinaryFormatter
SerializableAttribute  標記 不需要 需要
ISerializable 接口 不需要實現,實現了也不起作用。 可以不實現,但實現了就起作用。
無參構造函數 必須有,系統提供的缺省無參構造函數也算。 不需要,因爲反序列化時不調用構造函數。
被序列化的數據成員 公共屬性和字段 所有
產生文件大小

    XML序列化的優點是使用簡單,也頗具靈活性,比如可以控制數據在 XML 文件中是作爲 Element 還是作爲 Attribute ,以及顯示的名稱等。XML 序列化對一般的應用是足以應付的,但當序列化循環引用的對象,即有多個引用指向同一個對象實體時,XML 序列化機制將在每個引用的地方都創建一個對象副本。這除了會導致數據存儲上的冗餘外,更嚴重的是使一個對象在反序列化後變成了毫無關係的多個對象,即 XML 反序列化後可能得到錯誤的對象關係圖表。比如下圖所示的簡單例子: 
 

    對應三種類型分別有三個對象 cObject 及其成員 _aObject、 _bObject,_aObject 由 cObject 構造,_bObject 中存的是對 _aObject 的引用,即 cObject 的成員 _aObject 和 _bObject 的成員 _aObject 是同一個東西。則 ClassC 類型的對象 cObject 經 XML 序列化的結果是:
<ClassC xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
  
<Name>ccc</Name> 
  
<AObject> 
    
<ID>37</ID> 
    
<Name>aaa</Name> 
  
</AObject> 
  
<BObject> 
    
<Name>bbb</Name> 
    
<AObject> 
      
<ID>37</ID> 
      
<Name>aaa</Name> 
    
</AObject> 
  
</BObject> 
</ClassC> 
     
    從這個結果反序列化後得到的新的 cObject,其成員 _aObject 跟 _bObject 中的 _aObject 可就是兩個對象了。要解決這個問題,我能想到的就是給對象加上 GUID 屬性,在反序列化後根據 GUID 屬性重新設置引用,不知還有沒有其它辦法。 
    
    SOAP 和二進制序列化的優點是可以精確地控制序列化及反序列化的過程,並可以序列化對象的非公共成員。所以對複雜對象的序列化,我們應該在實現 ISerializable 接口後,用 SOAP 或 二進制的方式保存數據。至於缺點,如果你嫌在類名上加個 Serializable 標記很麻煩的話,這也許算個缺點。 
    還是上面的例子,如果用 SOAP 序列化 cObject 對象,結果是: 
<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:ClassC id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SerializeTest.CrossReference/SerializeTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"> 
            
<ClassCNameName id="ref-3">ccc</ClassCNameName> 
            
<ClassCAObjectAObject href="#ref-4"/> 
            
<ClassCBObjectBObject href="#ref-5"/> 
        
</a1:ClassC> 
        
<a1:ClassA id="ref-4" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SerializeTest.CrossReference/SerializeTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"> 
            
<ClassANameName id="ref-6">aaa</ClassANameName> 
            
<ClassAIDID>37</ClassAIDID> 
        
</a1:ClassA> 
        
<a1:ClassB id="ref-5" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/SerializeTest.CrossReference/SerializeTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"> 
            
<ClassBNameName id="ref-7">bbb</ClassBNameName> 
            
<ClassBAObjectAObject href="#ref-4"/> 
        
</a1:ClassB> 
    
</SOAP-ENV:Body> 
</SOAP-ENV:Envelope> 

    很明顯,裏面存的是對象引用,這是一個精確副本,反序列化後毫無問題。 

 附:ClassC 的一段代碼: 
        public ClassC()
        
{
            _name 
= "Unknown ClassC Object";
            InitData();
        }


        
private void InitData()
        
{
            _aObject 
= new ClassA( 1 );
            _aObject.Name 
= "aaa";
            _aObject.ID 
= 37;

            _bObject 
= new ClassB();
            _bObject.Name 
= "bbb";
            _bObject.AObject 
= _aObject;
        }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章