c#序列化和反序列化


   一、概述
   
當兩個進程在進行遠程通信時,彼此可以發送各種類型的數據。無論是何種類型的數據,都會以二進制序列的形式在網絡上傳送。發送方需要把這個對象轉換為字節序列,才能在網絡上傳送;接收方則需要把字節序列再恢復為對象。
    把對象轉換為字節序列的過程稱為
對象的序列化。
    把字節序列恢復為對象的過程稱為對象的反序列化。

   二、對象的序列化主要有兩種用途:
 
  1) 把對象的字節序列永久地保存到硬盤上,通常存放在一個文件中;
   
我們經常需要將對象的字段值保存到磁盤中,並在以后檢索此數據。盡管不使用序列化也能完成這項工作,但這種方法通常很繁瑣而且容易出錯,並且在需要跟蹤對象的層次結構時,會變得越來越復雜。可以想象一下編寫包含大量對象的大型業務應用程序的情形,程序員不得不為每一個對象編寫代碼,以便將字段和屬性保存至磁盤以及從磁 盤還原這些字段和屬性。序列化提供了輕松實現這個目標的快捷方法。公共語言運行時 (CLR) 管理對象在內存中的分布,.NET 框架則通過使用反射提供自動的序列化機制。對象序列化后,類的名稱、程序集以及類實例的所有數據成員均被寫入存儲媒體中。對象通常用成員變量來存儲對其他實例的引用。類序列化后,序列化引擎將跟蹤所有已序列化的引用對象,以確保同一對象不被序列化多次。.NET 框架所提供的序列化體系結構可以自動正確處理對象圖表和循環引用。對對象圖表的唯一要求是,由正在進行序列化的對象所引用的所有對象都必須標記為 Serializable(請參閱基 本序列化)。否則,當序列化程序試圖序列化未標記的對象時將會出現異常。當反序列化已序列化的類時,將重新創建該類,並自動還原所有數據成員的值。
  2) 在網絡上傳送對象的字節序列。
  
對象僅在創建對象的應用程序域中有效。除非對象是從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; 
     } 
 

  [BinarySerializer]

將此類的一個實例序列化為一個文件:  

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(); 

 

   反序列化:

IFormatter formatter = new BinaryFormatter(); 
 Stream stream = new FileStream("MyFile.bin", FileMode.Open, 
 FileAccess.Read, FileShare.Read); 
 MyObject obj = (MyObject) formatter.Deserialize(fromStream); 
 stream.Close(); 

 

  [XMLSerializer]   

將此類的實例序列化成一個Xml文件.

XmlSerializer ser = new XmlSerializer(obj.GetType());
 ser.Serialize(new FileStream(@"users.xml", FileMode.Create), obj);

 

   反序列化:

XmlSerializer serializer = new XmlSerializer(Type.GetType("MyObject"));
 MyObject my=(MyObject)serializer.Deserialize(new FileStream(@"users.xml",FileMode.Open));

 

    說明:使用二進制格式化程序進行序列化。您只需創建一個要使用的流和格式化程序的實例,然后調用格式化程序的 Serialize 方法。流和要序列化的對象實例作為參數提供給此調用。類中的所有成員變量(甚至標記為 private 的變量)都將被序列化,但這一點在本例中未明確體現出來。在這一點上,二進制序列化不同於只序列化公共字段的 XML 序列化程序。將對象還原到它以前的狀態也非常容易。首先,創建格式化程序和流以進行讀取,然后讓格式化程序對對象進行反序列化。       

[SOAP Serializer]  

  如果要求具有可移植性,請使用 SoapFormatter。所要做的更改只是將以上代碼中的BinaryFormatter換 SoapFormatter,而 Serialize 和 Deserialize 調用不變。

 

序列化和反序列化我們可能經常會聽到,其實通俗一點的解釋,序列化就是把一個對象保存到一個文件或數據庫字段中去,反序列化就是在適當的時候把這個文件再轉化成原來的對象使用。 我想最主要的作用有: 1、在進程下次啟動時讀取上次保存的對象的信息 2、在不同的AppDomain或進程之間傳遞數據 3、在分布式應用系統中傳遞數據 ...... 在C#中常見的序列化的方法主要也有三個:BinaryFormatter、SoapFormatter、XML序列化 本文就通過一個小例子主要說說這三種方法的具體使用和異同點
這個例子就是使用三種不同的方式把一個Book對象進行序列化和反序列化,當然這個Book類首先是可以被序列化的。至於怎么使一個類可以序列化可以參見:C#強化系列文章一:ViewState使用兼談序列化

Book類

這個類比較簡單,就是定義了一些public字段和一個可讀寫的屬性,一個private字段,一個標記為[NonSerialized]的字段,具體會在下面的例子中體現出來
一、BinaryFormatter序列化方式1、序列化,就是給Book類賦值,然后進行序列化到一個文件中

            Book book = new Book();             book.BookID = " 1 " ;             book.alBookReader.Add( " gspring " );             book.alBookReader.Add( " 永春 " );             book.strBookName = " C#強化 " ;             book.strBookPwd = " ***** " ;             book.SetBookPrice( " 50.00 " );             BinarySerialize serialize = new BinarySerialize();             serialize.Serialize(book);

2、反序列化

            BinarySerialize serialize = new BinarySerialize();             Book book = serialize.DeSerialize();             book.Write();

3、測試用的

BinarySerialize類

主要就是調用System.Runtime.Serialization.Formatters.Binary空間下的BinaryFormatter類進行序列化和反序列化,以縮略型二進制格式寫到一個文件中去,速度比較快,而且寫入后的文件已二進制保存有一定的保密效果。 調用反序列化后的截圖如下: 也就是說除了標記為NonSerialized的其他所有成員都能序列化
二、SoapFormatter序列化方式調用序列化和反序列化的方法和上面比較類似,我就不列出來了,主要就看看SoapSerialize類

SoapSerialize類

主要就是調用System.Runtime.Serialization.Formatters.Soap空間下的SoapFormatter類進行序列化和反序列化,使用之前需要應用System.Runtime.Serialization.Formatters.Soap.dll(.net自帶的) 序列化之后的文件是Soap格式的文件(簡單對象訪問協議(Simple Object Access Protocol,SOAP),是一種輕量的、簡單的、基於XML的協議,它被設計成在WEB上交換結構化的和固化的信息。 SOAP 可以和現存的許多因特網協議和格式結合使用,包括超文本傳輸協議(HTTP),簡單郵件傳輸協議(SMTP),多用途網際郵件擴充協議(MIME)。它還支持從消息系統到遠程過程調用(RPC)等大量的應用程序。SOAP使用基於XML的數據結構和超文本傳輸協議(HTTP)的組合定義了一個標准的方法來使用Internet上各種不同操作環境中的分布式對象。) 調用反序列化之后的結果和方法一相同
三、XML序列化方式調用序列化和反序列化的方法和上面比較類似,我就不列出來了,主要就看看XmlSerialize類

XmlSerialize類

從這三個測試類我們可以看出來其實三種方法的調用方式都差不多,只是具體使用的類不同 xml序列化之后的文件就是一般的一個xml文件:

book.xml

輸出截圖如下: 也就是說采用xml序列化的方式只能保存public的字段和可讀寫的屬性,對於private等類型的字段不能進行序列化
關於循環引用: 比如在上面的例子Book類中加入如下一個屬性:         public Book relationBook;在調用序列化時使用如下方法:

            Book book = new Book();             book.BookID = " 1 " ;             book.alBookReader.Add( " gspring " );             book.alBookReader.Add( " 永春 " );             book.strBookName = " C#強化 " ;             book.strBookPwd = " ***** " ;             book.SetBookPrice( " 50.00 " );             Book book2 = new Book();             book2.BookID = " 2 " ;             book2.alBookReader.Add( " gspring " );             book2.alBookReader.Add( " 永春 " );             book2.strBookName = " .NET強化 " ;             book2.strBookPwd = " ***** " ;             book2.SetBookPrice( " 40.00 " );             book.relationBook = book2;             book2.relationBook = book;             BinarySerialize serialize = new BinarySerialize();             serialize.Serialize(book);

這樣就會出現循環引用的情況,對於BinarySerialize和SoapSerialize可以正常序列化(.NET內部進行處理了),對於XmlSerialize出現這種情況會報錯:"序列化類型 SerializableTest.Book 的對象時檢測到循環引用。"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM