.NET 中的對象序列化_第1頁
.NET 中的對象序列化_第2頁
.NET 中的對象序列化_第3頁
.NET 中的對象序列化_第4頁
.NET 中的對象序列化_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、.NET 中的對象序列化 作者:Piet Obermeyer文章來源:microsoft 摘要:為什么要使用序列化?最重要的兩個原因是:將對象的狀態(tài)保存在存儲媒體中以便可以在以后重新創(chuàng)建出完全相同的副本;按值將對象從一個應用程序域發(fā)送至另一個應用程序域。例如,序列化可用于在 ASP.NET 中保存會話狀態(tài),以及將對象復制到 Windows 窗體的剪貼板中。它還可用于按值將對象從一個應用程序域遠程傳遞至另一個應用程序域。本文簡要介紹了 Microsoft .NET 中使用的序列化。 目錄 簡介 持久存儲 按值封送 基本序列化 選擇性序列化 自定義序列化 序列化過程的步驟 版本

2、控制 序列化規(guī)則簡介序列化是指將對象實例的狀態(tài)存儲到存儲媒體的過程。在此過程中,先將對象的公共字段和私有字段以及類的名稱(包括類所在的程序集)轉換為字節(jié)流,然后再把字節(jié)流寫入數(shù)據(jù)流。在隨后對對象進行反序列化時,將創(chuàng)建出與原對象完全相同的副本。在面向對象的環(huán)境中實現(xiàn)序列化機制時,必須在易用性和靈活性之間進行一些權衡。只要您對此過程有足夠的控制能力,就可以使該過程在很大程度上自動進行。例如,簡單的二進制序列化不能滿足需要,或者,由于特定原因需要確定類中那些字段需要序列化。以下各部分將探討 .NET 框架提供的可靠的序列化機制,并著重介紹使您可以根據(jù)需要自定義序列化過程的一些重要功能。持久存儲我們經(jīng)

3、常需要將對象的字段值保存到磁盤中,并在以后檢索此數(shù)據(jù)。盡管不使用序列化也能完成這項工作,但這種方法通常很繁瑣而且容易出錯,并且在需要跟蹤對象的層次結構時,會變得越來越復雜??梢韵胂笠幌戮帉懓罅繉ο蟮拇笮蜆I(yè)務應用程序的情形,程序員不得不為每一個對象編寫代碼,以便將字段和屬性保存至磁盤以及從磁盤還原這些字段和屬性。序列化提供了輕松實現(xiàn)這個目標的快捷方法。公共語言運行時 (CLR 管理對象在內存中的分布,.NET 框架則通過使用反射提供自動的序列化機制。對象序列化后,類的名稱、程序集以及類實例的所有數(shù)據(jù)成員均被寫入存儲媒體中。對象通常用成員變量來存儲對其他實例的引用。類序列化后,序列化引擎將跟蹤

4、所有已序列化的引用對象,以確保同一對象不被序列化多次。.NET 框架所提供的序列化體系結構可以自動正確處理對象圖表和循環(huán)引用。對對象圖表的唯一要求是,由正在進行序列化的對象所引用的所有對象都必須標記為 Serializable(請參閱基本序列化)。否則,當序列化程序試圖序列化未標記的對象時將會出現(xiàn)異常。當反序列化已序列化的類時,將重新創(chuàng)建該類,并自動還原所有數(shù)據(jù)成員的值。按值封送對象僅在創(chuàng)建對象的應用程序域中有效。除非對象是從 MarshalByRefObject 派生得到或標記為 Serializable,否則,任何將對象作為參數(shù)傳遞或將其作為結果返回的嘗試都將失敗。如果對象標記為 Seri

5、alizable,則該對象將被自動序列化,并從一個應用程序域傳輸至另一個應用程序域,然后進行反序列化,從而在第二個應用程序域中產(chǎn)生出該對象的一個精確副本。此過程通常稱為按值封送。如果對象是從 MarshalByRefObject 派生得到,則從一個應用程序域傳遞至另一個應用程序域的是對象引用,而不是對象本身。也可以將從 MarshalByRefObject 派生得到的對象標記為 Serializable。遠程使用此對象時,負責進行序列化并已預先配置為 SurrogateSelector 的格式化程序將控制序列化過程,并用一個代理替換所有從 MarshalByRefObject 派生得到的對象。

6、如果沒有預先配置為 SurrogateSelector,序列化體系結構將遵從下面的標準序列化規(guī)則(請參閱序列化過程的步驟)?;拘蛄谢挂粋€類可序列化,最簡單的方法是使用 Serializable 屬性對它進行標記,如下所示:Serializablepublic 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 = &

7、quot;一些字符串"IFormatter formatter = new BinaryFormatter(;Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None;formatter.Serialize(stream, obj;stream.Close(;本例使用二進制格式化程序進行序列化。您只需創(chuàng)建一個要使用的流和格式化程序的實例,然后調用格式化程序的 Serialize 方法。流和要序列化的對象實例作為參數(shù)提供給此調用。類中的

8、所有成員變量(甚至標記為 private 的變量)都將被序列化,但這一點在本例中未明確體現(xiàn)出來。在這一點上,二進制序列化不同于只序列化公共字段的 XML 序列化程序。將對象還原到它以前的狀態(tài)也非常容易。首先,創(chuàng)建格式化程序和流以進行讀取,然后讓格式化程序對對象進行反序列化。以下代碼片段說明了如何進行此操作。IFormatter formatter = new BinaryFormatter(;Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read;

9、MyObject obj = (MyObject formatter.Deserialize(fromStream;stream.Close(;/ 下面是證明Console.WriteLine("n1: 0", obj.n1;Console.WriteLine("n2: 0", obj.n2;Console.WriteLine("str: 0", obj.str;上面所使用的 BinaryFormatter 效率很高,能生成非常緊湊的字節(jié)流。所有使用此格式化程序序列化的對象也可使用它進行反序列化,對于序列化將在 .NET 平臺上進行反

10、序列化的對象,此格式化程序無疑是一個理想工具。需要注意的是,對對象進行反序列化時并不調用構造函數(shù)。對反序列化添加這項約束,是出于性能方面的考慮。但是,這違反了對象編寫者通常采用的一些運行時約定,因此,開發(fā)人員在將對象標記為可序列化時,應確保考慮了這一特殊約定。如果要求具有可移植性,請使用 SoapFormatter。所要做的更改只是將以上代碼中的格式化程序換成 SoapFormatter,而 Serialize 和 Deserialize 調用不變。對于上面使用的示例,該格式化程序將生成以下結果。xmlns:xsi=/2001/XMLSchema-instanc

11、e xmlns:xsd="/2001/XMLSchema" xmlns:SOAP- ENC=/soap/encoding/ xmlns:SOAP- ENV=/soap/envelope/ SOAP-ENV:encodingStyle= " /soap/encoding/" xmlns:a1=" 1 24 一些字符串需要注意的是,無法繼承 Serializable 屬

12、性。如果從 MyObject 派生出一個新的類,則這個新的類也必須使用該屬性進行標記,否則將無法序列化。例如,如果試圖序列化以下類實例,將會顯示一個 SerializationException,說明 MyStuff 類型未標記為可序列化。public class MyStuff : MyObject public int n3;使用序列化屬性非常方便,但是它存在上述的一些限制。有關何時標記類以進行序列化(因為類編譯后就無法再序列化),請參考有關說明(請參閱下面的序列化規(guī)則)。選擇性序列化類通常包含不應被序列化的字段。例如,假設某個類用一個成員變量來存儲線程 ID。當此類被反序列化時,序列化此

13、類時所存儲的 ID 對應的線程可能不再運行,所以對這個值進行序列化沒有意義。可以通過使用 NonSerialized 屬性標記成員變量來防止它們被序列化,如下所示:Serializablepublic class MyObject public int n1;NonSerialized public int n2;public String str;自定義序列化可以通過在對象上實現(xiàn) ISerializable 接口來自定義序列化過程。這一功能在反序列化后成員變量的值失效時尤其有用,但是需要為變量提供值以重建對象的完整狀態(tài)。要實現(xiàn) ISerializable,需要實現(xiàn) GetObjectData

14、 方法以及一個特殊的構造函數(shù),在反序列化對象時要用到此構造函數(shù)。以下代碼示例說明了如何在前一部分中提到的 MyObject 類上實現(xiàn) ISerializable。Serializablepublic class MyObject : ISerializable public int n1;public int n2;public String str;public MyObject(protected MyObject(SerializationInfo info, StreamingContext contextn1 = info.GetInt32("i"n2 = inf

15、o.GetInt32("j"str = info.GetString("k"public virtual void GetObjectData(SerializationInfo info, StreamingContext contextinfo.AddValue("i", n1;info.AddValue("j", n2;info.AddValue("k", str;在序列化過程中調用 GetObjectData 時,需要填充方法調用中提供的 SerializationInfo 對象。只需按

16、名稱/值對的形式添加將要序列化的變量。其名稱可以是任何文本。只要已序列化的數(shù)據(jù)足以在反序列化過程中還原對象,便可以自由選擇添加至 SerializationInfo 的成員變量。如果基對象實現(xiàn)了 ISerializable,則派生類應調用其基對象的 GetObjectData 方法。 需要強調的是,將 ISerializable 添加至某個類時,需要同時實現(xiàn) GetObjectData 以及特殊的構造函數(shù)。如果缺少 GetObjectData,編譯器將發(fā)出警告。但是,由于無法強制實現(xiàn)構造函數(shù),所以,缺少構造函數(shù)時不會發(fā)出警告。如果在沒有構造函數(shù)的情況下嘗試反序列化某個類,將會出現(xiàn)異常。在消除潛

17、在安全性和版本控制問題等方面,當前設計優(yōu)于 SetObjectData 方法。例如,如果將 SetObjectData 方法定義為某個接口的一部分,則此方法必須是公共方法,這使得用戶不得不編寫代碼來防止多次調用 SetObjectData 方法。可以想象,如果某個對象正在執(zhí)行某些操作,而某個惡意應用程序卻調用此對象的 SetObjectData 方法,將會引起一些潛在的麻煩。在反序列化過程中,使用出于此目的而提供的構造函數(shù)將 SerializationInfo 傳遞給類。對象反序列化時,對構造函數(shù)的任何可見性約束都將被忽略,因此,可以將類標記為 public、protected、interna

18、l 或 private。一個不錯的辦法是,在類未封裝的情況下,將構造函數(shù)標記為 protect。如果類已封裝,則應標記為 private。要還原對象的狀態(tài),只需使用序列化時采用的名稱,從 SerializationInfo 中檢索變量的值。如果基類實現(xiàn)了 ISerializable,則應調用基類的構造函數(shù),以使基礎對象可以還原其變量。如果從實現(xiàn)了 ISerializable 的類派生出一個新的類,則只要新的類中含有任何需要序列化的變量,就必須同時實現(xiàn)構造函數(shù)以及 GetObjectData 方法。以下代碼片段顯示了如何使用上文所示的 MyObject 類來完成此操作。Serializablep

19、ublic class ObjectTwo : MyObjectpublic int num;public ObjectTwo( : base(protected ObjectTwo(SerializationInfo si, StreamingContext context : base(si,contextnum = si.GetInt32("num"public override void GetObjectData(SerializationInfo si, StreamingContext contextbase.GetObjectData(si,context;

20、si.AddValue("num", num;切記要在反序列化構造函數(shù)中調用基類,否則,將永遠不會調用基類上的構造函數(shù),并且在反序列化后也無法構建完整的對象。對象被徹底重新構建,但是在反系列化過程中調用方法可能會帶來不良的副作用,因為被調用的方法可能引用了在調用時尚未反序列化的對象引用。如果正在進行反序列化的類實現(xiàn)了 IDeserializationCallback,則反序列化整個對象圖表后,將自動調用 OnSerialization 方法。此時,引用的所有子對象均已完全還原。有些類不使用上述事件偵聽器,很難對它們進行反序列化,散列表便是一個典型的例子。在反序列化過程中檢索

21、關鍵字/值對非常容易,但是,由于無法保證從散列表派生出的類已反序列化,所以把這些對象添加回散列表時會出現(xiàn)一些問題。因此,建議目前不要在散列表上調用方法。序列化過程的步驟在格式化程序上調用 Serialize 方法時,對象序列化按照以下規(guī)則進行: 檢查格式化程序是否有代理選取器。如果有,檢查代理選取器是否處理指定類型的對象。如果選取器處理此對象類型,將在代理選取器上調用 ISerializable.GetObjectData。 如果沒有代理選取器或有卻不處理此類型,將檢查是否使用 Serializable 屬性對對象進行標記。如果未標記,將會引發(fā) SerializationException。 如果對象已被正確標記,將檢查對象是否實現(xiàn)了 ISerializable。如果已實現(xiàn),將在對象上調用 GetObjectData。 如果對象未實現(xiàn) Serializable,將使用默認的序列化策略,對所有未標記為 NonSerialized 的字段都進行序列化。 版本控制.NET 框架支持版本控制和并排執(zhí)行,并且,如果類的接口保持一致,所有類均可跨版本工作。由于序列化涉及的是成員變量而非接口,所以,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論