淺析.NET中的Serialization(zhuan)

來源:互聯網
上載者:User

出處:PConline
責任編輯:ycx

[03-5-29 10:27]
作者:sam1111/ASPCool

摘要 本文簡要介紹了.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更加徹底,因為它是將儲存在對象私人變數裡的實際值拷貝到位元組流裡。而且Deep Serialization還將serialize整個object graph。也就是說,如果你的對象持有其他對象的引用,或者其他對象引用的集合,那麼所有這些對象都將被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屬性標記。如果沒有,則拋出SerializationException異常。
3、 如果對象被標記為Serializable,檢查對象是否實現了ISerializable介面。如果實現了此介面,則GetObjectData被調用。
4、 如果對象沒有實現ISerializable介面,則使用預設的序列化策略,來序列化沒有用NonSerialized屬性標記的域。

使你的class能夠被序列化
通過上面對Serialization過程的分析,我們可以看出,有兩種方式可以使一個class能夠被序列化:1)將此class簡單地標記為Serializable;2)為此class實現ISerializable介面,並將此class標記為Serializable。
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();
就是這麼簡單,你所要做的就是建立一個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的話,那麼這個衍生類別也必須被Serializable標記。否則將得到SerializationException異常。
同樣的,Person類中的所有對其他類的引用,其所引用的類都應該是能夠被Serialize的。.NET Framework中的大部分class都實現了ISerializable介面,但有些class沒有實現,例如ImageList。可以通過MSDN Library的到一個實現了ISerializable介面的class列表。對那些沒有實現此介面的class,使用的時候要當心。

 

2、 實現ISerializable介面
Serializable屬性的功能非常強大,它使得Serialize和Deserialize變得十分簡單。但凡事有利必有弊,由Serializable實現的自動序列化方法有時不夠靈活。我們並不能完全控制Serialize和Deserialize的行為,而有些時候它們的行為對我們來說很重要。那麼我們通過何種方法能夠控制Serialize和Deserialize的行為呢?答案就是,自己來實現ISerializable介面。ISerializable介面給予我們更大的自由來控制Serialize和Deserialize,但是無疑我們將不得不寫更多的代碼L。
下面我們來看看如何?ISerializabe介面。ISerializable介面位於System.Runtime.Serialization名字空間中,聲明如下:
public inferface ISerializable
{
void GetObjectData(SerializationInfo info,
StreamingContext context);
}
它只有一個方法GetObjectData。因此,像實現其他介面一樣,我們必須實現此方法。但與其他介面不同的是,為了Deserialization,我們還必須實現一個特殊的建構函式(我稱此建構函式為“序列化建構函式”),此建構函式具有與GetObjectData相同的參數列表。由於此建構函式專門用於.NET Framework在Deserialize時的Reflection機制,因此我們通常將它聲明為保護或私人模式。如下:(當然,如果你的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的行為,在“序列化建構函式”中控制Deserialize的行為。這個介面提供給我們的資訊非常全面而靈活,以致於我們甚至可以在這兩個方法中耍些花招。比如,我們可以在Deserialize的時候,籍由改變info.FullTypeName來得到一種與被Serialize的對象不同類型的另一個對象等。

 

獨闢蹊徑
前面談到過Serialization被運用的典型環境,是Object Storage Service、進程間資料傳遞等涉及到對象持久性的領域。但實際上,它也能夠被運用到其他的許多地方,關鍵在於我們是否能想到去用運Serialization,有時候思維定式也是很可怕的J。舉個例子,我們來看看在Clone方法中如何使用Serialization[1]。
如果我們要為Person類實現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方法似乎並沒有什麼好處。可是設想如果你面對的是一個複雜的類繼承體系,從基類到衍生類別都需要實現Clone方法。利用第一種實作手法,你將不得不為每一個class寫一個Clone方法,而且隨著資料成員的增多,這個方法將越來越冗長,並且會由於資料成員的改變而引發錯誤(我曾經遇到過好幾次,由於class中增加了成員變數,而Clone方法沒有及時更新,導致執行階段錯誤。呵呵,這種錯誤還很難調試)。現在你看到用Serialization實現的好處了吧?是的,我們只要在基類中將Clone方法聲明為virtual,並用Serialization的方法實現之,然後保證基類和衍生類別都可以被Serialize,上面所有的麻煩不都迎刃而解了嗎?
總結
現代軟體項目中,無論何種項目都會或多或少地涉及到對象持久性的問題,.NET也不例外,無論是Windows Form、ASP.NET,還是Web Services,都需要處理對象持久性。而Serialization正是.NET為應對這個問題而給出的解法。
參考文獻
·[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。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.