線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1508
推到 Plurk!
推到 Facebook!

淺析.NET中的Serialization

 
conundrum
尊榮會員


發表:893
回覆:1272
積分:643
註冊:2004-01-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-01-27 13:02:59 IP:61.221.xxx.xxx 未訂閱
http://www.skycn.com/article/1473.html 摘要 本文簡要介紹了.NET中的序列化(Serialization)概念,以及在代碼中實作Serialization的方法。文章的最後介紹了Serialization在Clone方法中的運用。 Serialization的概念 Serialization是.NET中一種實現物件持久性(Persistent)的機制。它是一個將物件中的資料轉換成一個單一元素(通常是Stream)的過程。它的逆過程是Deserialization。Serialization的核心概念是將一個物件的所有資料看作一個獨立的單元。 一般說來,在兩種情況下非常需要Serialization:1)當我們希望能夠將物件當前的狀態完整地保存到存儲介質中,以便我們以後能夠精確地還原物件時;2)當我們希望將物件從一個應用程式空間(Application domain)傳遞到另一個應用程式空間時。例如,Windows Form程式就是利用Serialization機制來實現剪貼板的copy & paste的。 .NET Framework支援兩種類型的Serialization:Shallow Serialization和Deep Serialization。 所謂Shallow Serialization是將物件的可讀寫(read-write)屬性的值轉換成位元組流,而物件內部的資料(沒有通過read-write屬性暴露出來的資料)則不被轉換。XmlSerializer以及Web Services就使用這種技術。 Deep Serialization比Shallow Serialization更加徹底,因d它是將存儲在物件私有變數裏的實際值拷貝到位元組流裏。而且Deep Serialization還將serialize整個object graph。也就是說,如果你的物件持有其他物件的引用,或者其他物件引用的集合,那l所有這些物件都將被Serialize。BinaryFormatter和SoapFormatter以及.NET Remoting都使用Deep Serialization技術,它甚至被有限地用於LosFormatter來{生存儲在Web Form頁中的狀態資料。 本文將著重於Deep Serialization。 Serialization的過程 .NET Framework通過Reflection提供自動Serialization的機制。當一個物件被序列化(Serialized)的時候,它的類名,Assembly,以及類實例的所有資料成員都將被寫入存儲介質中。Serialization引擎保持對所有已經被序列化的物件引用的追蹤,以確保相同的物件引用最多只被序列化一次。 通常,一個Serialization過程會由formatter(例如BinaryFormatter)的Serialize方法引發。物件的Serialization過程按照以下規則進行: 1、 檢測以確保formatter是否擁有一個代理選擇器(surrogate selector)。如果有,檢查代理選擇器是否持有給定的物件類型。如果有,ISerializable.GetObjectData被調用。 2、 如果formatter沒有代理選擇器,或者代理選擇器沒有物件類型,檢查物件是否被用Serializable屬性標記。如果沒有,則墨XSerializationException異常。 3、 如果物件被標記dSerializable,檢查物件是否實現了ISerializable介面。如果實現了此介面,則GetObjectData被調用。 4、 如果物件沒有實現ISerializable介面,則使用默認的序列化策略,來序列化沒有用NonSerialized屬性標記的域。 使你的class能夠被序列化 通過上面對Serialization過程的分析,我們可以看出,有兩種方式可以使一個class能夠被序列化:1)將此class簡單地標記dSerializable;2)d此class實現ISerializable介面,並將此class標記dSerializable。 1、 標記Serializable屬性 標記Serializable屬性的方式是實現Serialization的基本方法。舉個簡單的例子: [Serializable] public class Person { public string name = null; public int age = 0; } 你可以使用BinaryFormatter來將上面的class序列化: Person sam = new Person(); sam.name = "sam"; sam.age = 24; IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream("sam.dat", FileMode.Create, FileAccess.Write, FileShare.None); formatter.Serialize(stream, sam); stream.Close(); 就是這l簡單,你所要做的就是創建一個Stream和一個formatter的實例,然後調用formatter的Serialize方法。經過BinaryFormatter serialize的資料仍然能夠通過BinaryFormatter deserialize回來,方法與serialize同樣簡單,這裏就不贅述了。 如果你不想將類裏的所有域都序列化,可以使用NonSerialized屬性進行選擇。如: [Serializable] public class Person { public string name = null; [NonSerialized] public int age = 0; } 這樣,age域就不會被序列化了。 需要注意的是,Serializable屬性並不能被繼承。也就是說如果你希望Person的派生類也能夠被Serialize的話,那l這個派生類也必須被Serializable標記。否則將得到SerializationException異常。 同樣的,Person類中的所有對其他類的引用,其所引用的類都應該是能夠被Serialize的。.NET Framework中的大部分class都實現了ISerializable介面,但有些class沒有實現,例如ImageList。可以通過MSDN Library的到一個實現了ISerializable介面的class列表。對那些沒有實現此介面的class,使用的時候要當心。 2、 實現ISerializable介面 Serializable屬性的功能非常強大,它使得Serialize和Deserialize變得十分簡單。但凡事有利必有弊,由Serializable實現的自動序列化方法有時不夠靈活。我們並不能完全控制Serialize和Deserialize的行d,而有些時候它們的行d對我們來說很重要。那l我們通過何種方法能夠控制Serialize和Deserialize的行d呢?答案就是,自己來實現ISerializable介面。ISerializable介面給予我們更大的自由來控制Serialize和Deserialize,但是無疑我們將不得不寫更多的代碼L。 下面我們來看看如何實現ISerializabe介面。ISerializable介面位於System.Runtime.Serialization名字空間中,聲明如下: public inferface ISerializable { void GetObjectData(SerializationInfo info, StreamingContext context); } 它只有一個方法GetObjectData。因此,像實現其他介面一樣,我們必須實現此方法。但與其他介面不同的是,d了Deserialization,我們還必須實現一個特殊的構造函數(我稱此構造函數d“序列化構造函數”),此構造函數具有與GetObjectData相同的參數列表。由於此構造函數專門用於.NET Framework在Deserialize時的Reflection機制,因此我們通常將它聲明d保護或私有模式。如下:(當然,如果你的class只需要Serialize而不需要Deserialize的話,也可以不實現這個特殊的構造函數) [Serializable] public class Person : ISerializable { public string name = null; public int age = 0; public Person() { } protected Person(SerializationInfo info, StreamingContext context) { name = info.GetString("name"); age = info.GetInt32("age"); } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("name", name); info.AddValue("age", age); } } 通過實現ISerializable介面,使得我們有機會在ISerializable.GetObjectData中控制Serialize的行d,在“序列化構造函數”中控制Deserialize的行d。這個介面提供給我們的資訊非常全面而靈活,以致於我們甚至可以在這兩個方法中耍些花招。比如,我們可以在Deserialize的時候,籍由改變info.FullTypeName來得到一種與被Serialize的物件不同類型的另一個物件等。 獨闢蹊徑 前面談到過Serialization被運用的典型環境,是物件存儲、進程間資料傳遞等涉及到物件持久性的領域。但實際上,它也能夠被運用到其他的許多地方,關鍵在於我們是否能想到去用運Serialization,有時候思維定式也是很可怕的J。舉個例子,我們來看看在Clone方法中如何使用Serialization[1]。 如果我們要dPerson類實現Clone方法,我們通常會這樣寫: [Serializable] public class Person : ICloneable { public string name = null; public int age = 0; public object Clone() { Person person = new Person(); person.name = name; person.age = age; return person; } } 如果我們利用Serialization的方法,Clone函數就能寫成下面的樣子: public object Clone() { MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, this); stream.Position = 0; return formatter.Deserialize(stream); } 從這兩個實現上看,使用Serialization實現Clone方法似乎並沒有什l好處。可是設想如果你面對的是一個複雜的類繼承體系,從基類到派生類都需要實現Clone方法。利用第一種實作手法,你將不得不d每一個class寫一個Clone方法,而且隨著資料成員的增多,這個方法將越來越冗長,並且會由於資料成員的改變而引發錯誤(我曾經遇到過好幾次,由於class中增加了成員變數,而Clone方法沒有及時更新,導致運行時錯誤。呵呵,這種錯誤還很難調試)。現在你看到用Serialization實現的好處了吧?是的,我們只要在基類中將Clone方法聲明dvirtual,並用Serialization的方法實現之,然後保證基類和派生類都可以被Serialize,上面所有的麻煩不都迎刃而解了嗎? 總結 現代軟體專案中,無論何種專案都會或多或少地涉及到物件持久性的問題,.NET也不例外,無論是Windows Form、ASP.NET,還是Web Services,都需要處理物件持久性。而Serialization正是.NETd應對這個問題而給出的解法。 參考文獻 ·[1] Rockford Lhotka,《Object Serialization in Visual Basic .NET》,MSDN Library。Serialization在Clone方法中的運用即來自此文。 ·Piet Obermeyer and Jonathan Hawkins,《Object Serialization in the .NET Framework》,MSDN Library。 ·Jeffrey Richter,《.NET Run-time Serialization》Part 1,Part 2,Part 3,MSDN Library。 發表人 - conundrum 於 2004/01/27 19:07:43
系統時間:2024-06-29 8:03:36
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!