最近為了換一份新工作,準備了不少筆試題。從筆試當中自己發現了不少基礎知識的盲點。很慶幸這樣的機會,可以讓自己對於基礎知識的理解又上升一個臺階。此文介紹C#裡面的序列化與反序列化的知識,如果你是大鳥,請口下留情。 首先,什麼是序列化與反序列化呢? 序列化就是將對象的狀態信息轉換為可以存儲或傳輸形式的過 ...
最近為了換一份新工作,準備了不少筆試題。從筆試當中自己發現了不少基礎知識的盲點。很慶幸這樣的機會,可以讓自己對於基礎知識的理解又上升一個臺階。此文介紹C#裡面的序列化與反序列化的知識,如果你是大鳥,請口下留情。
首先,什麼是序列化與反序列化呢?
序列化就是將對象的狀態信息轉換為可以存儲或傳輸形式的過程。其實就是將對象持久化,比如說把對象保存為二進位或者是XML的方式。可以將對象序列到流、磁碟、記憶體和網路等等。相反,反序列化則是將存儲或傳輸形式轉換為對象的過程。
那麼,運用序列化的好處又是什麼呢?
(1)以某種存儲形式(二進位或者是XML等)使對象持久化。序列化和反序列化用來保存記憶體中的數據,它不是C#中獨有的技術,比如win7的休眠就是該技術的應用,在C#程式中可以用來保存對象,和對象當前狀態,下次打開時通過反序列化獲得,一般用在伺服器啟動(反序列化)和關閉(序列化)時保存數據。
(2)使對象的傳遞更加容易,比如你用ajax向伺服器請求信息,伺服器可以直接將model對象通過序列化來輸出json字元串,也可以通過反序列化將你傳過去的json字元串組裝成對象,就免去了拼字元串和解析字元串的過程。
最後,在.Net裡面怎麼實現序列化技術?
(1)二進位序列化保持類型保真度,這對於在應用程式的不同調用之間保留對象的狀態很有用。例如,通過將對象序列化到剪貼板,可在不同的應用程式之間共用對象。您可以將對象序列化到流、磁碟、記憶體和網路等等。
(2) XML 序列化僅序列化公共屬性和欄位,且不保持類型保真度。當您要提供或使用數據而不限制使用該數據的應用程式時,這一點是很有用的。由於 XML 是一個開放式標準,因此,對於通過 Web 共用數據而言,這是一個很好的選擇。SOAP 同樣是一個開放式標準,這使它也成為一個頗具吸引力的選擇。----------以上內容摘自百科的內容與百度的內容.
關於這兩點的概念,我自己也不大明白是什麼意思?
保持類型保真度,一開始我是認為是成員變數的類型,以為用XML序列化的話,都會變成是string的類型,但是發現根本不是這樣。成員變數的類型都能保存,那這裡說的類型保真類到底是指什麼?XML序列化僅序列化公共屬性和欄位,但是我用私有欄位,發現也一樣可以序列化。我是定義一個私有欄位,然後通過公共屬性來給它賦值,然後在反序列化裡面通過公共屬性來取私有欄位的內容,發現是可以的,不知道是不是我的理解有什麼問題?
1#針對二進位序列化與反序列化,.Net是使用BinaryFormatter對象來進行序列化與反序列化。
一般的實現方法,是把可序列化的類用特征類[Serializable]來標誌,當然,不想序列類的成員,可以用[NonSerialized]特征類來標誌。類裡面的所有成員變數都能被序列化。然後實例化命名空間System.Runtime.Serialization.Formatters.Binary下的BinaryFormatter對象,藉助其Serialize方法來實現序列化與Deserialize方法來實現反序列化。
using System; using System.IO; using System.Collections; using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization; [Serializable] public class SerializeObject { public int ID { get; set; } public string UserName { get; set; } public string Password { get; set; } [NonSerialized] public string notSerialize; } public class App { [STAThread] static void Main() { Serialize(); Deserialize(); } static void Serialize() { SerializeObject serializeObject = new SerializeObject(); serializeObject.ID = 1; serializeObject.UserName = "csdbfans"; serializeObject.Password = "csdbfans"; serializeObject.notSerialize = "博客園"; FileStream fs = new FileStream("DataFile.dat", FileMode.Create); BinaryFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(fs, serializeObject); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } finally { fs.Close(); } } static void Deserialize() { SerializeObject serializeObject = null; FileStream fs = new FileStream("DataFile.dat", FileMode.Open); try { BinaryFormatter formatter = new BinaryFormatter(); serializeObject = (SerializeObject)formatter.Deserialize(fs); } catch (SerializationException e) { Console.WriteLine("Failed to deserialize. Reason: " + e.Message); throw; } finally { fs.Close(); } Console.WriteLine("反序列Serializable的結果:ID->" + serializeObject.ID + ", UserName->"
+ serializeObject.UserName + ", Password->" + serializeObject.Password); Console.WriteLine("反序列化NonSerialized結果:" + serializeObject.notSerialize); } }
結果為:
其實你如果進到DataFile.dat文件的話,你會發現用記事本,寫字板來打開的話,都是會出現亂碼。因為它是用二進位的方式來保存的,所以你只有是在用二進位的方式下才能看到裡面的內容。不過對於我們來說,即使看到二進位的內容,我們也不大可能知道是什麼意思。所以可能只有通過反序列化的方式來讀出文檔的內容。
2#針對XML序列化與反序列化,.Net提供了兩種方式來實現。
其一:使用XmlSerializer類將對象序列化到XML文檔中和從XML文檔反序列化出對象。
與第1點的區別,摘自寒江笠博文:
(I)不使用[Serializable]特征類與[NonSerializable]特征類,只使用特征類[System.Xml.Serialization.XmlIgnoreAttribute] 來標誌哪些成員變數不需要被序列化。
(II)不能序列化私有成員變數(不確定,因為我試過可以)
(III)要求被序列化的類要有一個預設的構造函數(不確定,不知道這裡的構造函數是為了什麼而需要的)
using System; using System.IO; using System.Collections; using System.Xml.Serialization; using System.Runtime.Serialization; public class SerializeObject { public int ID { get; set; } public string UserName { get; set; } public string Password { get; set; } [XmlIgnoreAttribute] public string notSerialize; } public class App { [STAThread] static void Main() { Serialize(); Deserialize(); } static void Serialize() { SerializeObject serializeObject = new SerializeObject(); serializeObject.ID = 1; serializeObject.UserName = "csdbfans"; serializeObject.Password = "csdbfans"; serializeObject.notSerialize = "博客園"; FileStream fs = new FileStream("DataFile.xml", FileMode.Create); XmlSerializer formatter = new XmlSerializer(typeof(SerializeObject)); try { formatter.Serialize(fs, serializeObject); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } finally { fs.Close(); } } static void Deserialize() { SerializeObject serializeObject = null; FileStream fs = new FileStream("DataFile.xml", FileMode.Open); try { XmlSerializer formatter = new XmlSerializer(typeof(SerializeObject)); serializeObject = (SerializeObject)formatter.Deserialize(fs); } catch (SerializationException e) { Console.WriteLine("Failed to deserialize. Reason: " + e.Message); throw; } finally { fs.Close(); } Console.WriteLine("反序列Serializable的結果:ID->" + serializeObject.ID + ", UserName->"
+ serializeObject.UserName + ", Password->" + serializeObject.Password); Console.WriteLine("反序列化NonSerialized結果:" + serializeObject.notSerialize); } }
結果:
其二:使用SoapFormatter類將對象序列化到XML文檔中和從XML文檔反序列化出對象。
同樣是序列化到XML文檔裡面,只不過序列化裡面包含了SOAP特有的額外信息。
SoapFormatter 和 BinaryFormatter 兩個類實現 IRemotingFormatter 介面以支持遠程過程調用 (RPC),實現 IFormatter 介面(由 IRemotingFormatter 繼承)以支持對象圖形的序列化。SoapFormatter 類還支持對 ISoapMessage 對象進行 RPC,而不必使用 IRemotingFormatter 功能。此概念來自MSDN文檔,有興趣請點擊去研讀詳細內容。
其二的方法跟第一點(1#)的實現方法基本一樣,畢竟都是實現相同的介面,有一定的共性,只是最終存儲的格式或者是傳輸的方式不一樣。
using System; using System.IO; using System.Collections; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Soap; [Serializable] public class SerializeObject { public int ID { get; set; } public string UserName { get; set; } public string Password { get; set; } [NonSerialized] public string notSerialize; } public class App { [STAThread] static void Main() { Serialize(); Deserialize(); } static void Serialize() { SerializeObject serializeObject = new SerializeObject(); serializeObject.ID = 1; serializeObject.UserName = "csdbfans"; serializeObject.Password = "csdbfans"; serializeObject.notSerialize = "博客園"; FileStream fs = new FileStream("DataFile.soap", FileMode.Create); SoapFormatter formatter = new SoapFormatter(); try { formatter.Serialize(fs, serializeObject); } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } finally { fs.Close(); } } static void Deserialize() { SerializeObject serializeObject = null; FileStream fs = new FileStream("DataFile.soap", FileMode.Open); try { SoapFormatter formatter = new SoapFormatter(); serializeObject = (SerializeObject)formatter.Deserialize(fs); } catch (SerializationException e) { Console.WriteLine("Failed to deserialize. Reason: " + e.Message); throw; } finally { fs.Close(); } Console.WriteLine("反序列Serializable的結果:ID->" + serializeObject.ID + ", UserName->"
+ serializeObject.UserName + ", Password->" + serializeObject.Password); Console.WriteLine("反序列化NonSerialized結果:" + serializeObject.notSerialize); } }
結果為:
<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:SerializeObject id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/assem/MyTest%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"> <_x003C_ID_x003E_k__BackingField>1</_x003C_ID_x003E_k__BackingField> <_x003C_UserName_x003E_k__BackingField id="ref-3">csdbfans</_x003C_UserName_x003E_k__BackingField> <_x003C_Password_x003E_k__BackingField href="#ref-3"/> </a1:SerializeObject> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
這裡使用寒江笠博文來進行兩種技術的對比:
二進位序列化的優點:
(1)所有的類成員變數(包括只讀的)都可以被序列化
(2)性能非常好
XML序列化的優點:
(1)互操作性好
(2)不需要嚴格的二進位依賴
(3)可讀性強
這是我學習序列化與反序列化的一個過程,文中引用了不少“前人”的結果,但是文中還是有些內容不是很懂,希望還是能給大家帶來幫助,哪怕是一丁點,也足矣!如果你也喜歡,轉載時,請標明出處,謝謝!