NET可以讓我們很容易地存儲對象的狀態。
by Billy Hollis
注:Billy Hollis於9月18日在Orlando的VBITS大會上發表了“Objects in the Real World”。本篇技巧就來自那次大會。該大會也包含了其它關於對象編程的實際技巧,如運用Shadows關鍵字來修補對象接口以及如何下載編譯程序時不能得到的窗體和類。
只要我們運用對象,我們就需要存儲它們的表現形式。也許我們暫時不需要一個對象,我們不想讓它散亂地放在內存中。或者我們可能需要把一個對象實例從一個系統傳送到另一個系統。
對於所有這些情況,對象的狀態就需要以某種形式來體現,可以以不定的形式保存起來,或者傳送到另一個系統。通常,我們把對象的狀態信息作為一系列數據字節來存儲。
存儲一個對象狀態的過程就叫做“串行化”。運用這個狀態信息來創建一個新的、相等的對象實例就叫做“反串行化”。在VB6及更早的版本中,你必須編寫你自己的邏輯來執行這些操作。盡管有這麼多編程工作要做,但串行化在.Net中是自動的。
如果你在一個類的前面放一個
屬性,那麼一個對象實例就可以自動地被串行化了。你將這個屬性放置在一個類的聲明部分,如下: _
Public Class MyClassName
你也可以通過實現一個叫做ISerializable的接口來串行化一個對象,但這種方法更復雜。在大多數情況下,運用屬性更容易,也很有效。
一旦一個類被標記了屬性,我們就可以存儲它的狀態了。如果你運用另一個叫做Formatter的類,你可以將一個.NET對象實例的狀態作為一系列字節存儲起來,可以存儲在磁盤上或一個數據庫中,可以運用.Net Remoting或消息隊列從一個系統傳送到另一個系統。然後,另外的那個Formatter類就可以從串行化的狀態信息“重建”對象實例了。
不同類型的串行化有不同的Formatter類。BinaryFormatter保存一個對象的所有的內部狀態,包括私有變量。這就叫做“深串行化(deep serialization)”。XMLFormatter只保存公有屬性和數據成員,這個過程叫做“淺串行化(shallow serialization)”。還有用於其它目的的formatters。運用何種formatter取決於你的對象是否有重建對象實例所必須的內部狀態信息,以及你打算用串行化信息做什麼。
Formatter對象有Serialize和Deserialize方法。Serialize方法有兩個參數——一個放置狀態信息字節的對象流和要被串行化的對象實例。Deserizlize方法對包含狀態信息字節的對象流進行處理並將新的重建的對象實例作為一個普通的Object類型返回。然後,我們可以用CType方法將新的實例轉化成適當的類型。
因此,要想把你的對象信息存儲到磁盤上的一個文件,你可能需要下面的邏輯:
Dim myFileStream As New _
FileStream("C:\MyFileName.dat", _
FileMode.CreateNew)
Dim MyFormatter As New BinaryFormatter()
MyFormatter.Serialize(myFileStream, MyObject)
然後你可以用這個邏輯來重建對象:
Dim myFileStream As New _
FileStream("C:\MyFileName.dat", _
FileMode.Open)
Dim MyFormatter As New BinaryFormatter()
Dim GenericObject As Object
GenericObject = _
MyFormatter.Deserialize(myFileStream)
Dim MyObject As MyObjectType
MyObject = CType(GenericObject, MyObjectType)
這時候,你就可以用這個對象了,它的行為同最初的對象實例的行為完全一樣。
有時侯,串行化的過程是自動的。例如,如果把一個對象實例放在一個消息隊列上,消息隊列上的實際數據是由從串行化對象而來的狀態信息字節組成的。MessageQueue對象有一個Formatter屬性來指定所運用的formatter類型。這就簡化了把一個對象放到一個消息隊列上的過程,只需一行代碼: MessageQueue1.Send(objMyObjectInstance, _
"A tag string for humans to read")
然後,另一個系統就可以從隊列上提取狀態信息,並創建一個相等的對象實例了。那個系統也必須有一個MessageQueue對象,它的Formatter屬性也必須同用來將信息放到隊列上的最初的MessageQueue對象的formatter屬性類型一致。
這有一點復雜。你需要兩個步驟:
MyQueueMessage = _
MessageQueue1.Receive(ATimeoutValue)
objMyReconstitutedInstance = _
CType(MyQueueMessage.Body, _
MyObjectsType)
第一步是從消息隊列提取串行化狀態信息,第二步是運用該信息來創建新的、相等的對象實例。然後,我們就可以像運用最初的對象實例一樣來運用新的對象了。
還有更多關於處理消息隊列的資料,例如如何來處理超時設定。MSDN上的一篇名為“The Queue Continuum”的文章講述了這方面的一些細節。然而,正如你所看到的,將對象串行化到消息隊列上以及反串行化來得到一個新的對象實例是很簡單的。