的過程.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
你可以使用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
這樣,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 infe***ce iserializable
它只有乙個方法getobjectdata。因此,像實現其他介面一樣,我們必須實現此方法。但與其他介面不同的是,為了deserialization,我們還必須實現乙個特殊的建構函式(我稱此建構函式為「序列化建構函式」),此建構函式具有與getobjectdata相同的引數列表。由於此建構函式專門用於.net framework在deserialize時的reflection機制,因此我們通常將它宣告為保護或私有模式。如下:(當然,如果你的class只需要serialize而不需要deserialize的話,也可以不實現這個特殊的建構函式)
[serializable]
public class person : iserializable
protected person(serializationinfo info, streamingcontext context)
void iserializable.getobjectdata(serializationinfo info,
streamingcontext context)
}通過實現iserializable介面,使得我們有機會在iserializable.getobjectdata中控制serialize的行為,在「序列化建構函式」中控制deserialize的行為。這個介面提供給我們的資訊非常全面而靈活,以致於我們甚至可以在這兩個方法中耍些花招。比如,我們可以在deserialize的時候,籍由改變info.fulltypename來得到一種與被serialize的物件不同型別的另乙個物件等。
獨闢蹊徑
前面談到過serialization被運用的典型環境,是物件儲存、程序間資料傳遞等涉及到物件永續性的領域。但實際上,它也能夠被運用到其他的許多地方,關鍵在於我們是否能想到去用運serialization,有時候思維定式也是很可怕的j。舉個例子,我們來看看在clone方法中如何使用serialization[1]。
如果我們要為person類實現clone方法,我們通常會這樣寫:
[serializable]
public class person : icloneable
}如果我們利用serialization的方法,clone函式就能寫成下面的樣子:
public object clone()
從這兩個實現上看,使用serialization實現clone方法似乎並沒有什麼好處。可是設想如果你面對的是乙個複雜的類繼承體系,從基類到派生類都需要實現clone方法。利用第一種實作手法,你將不得不為每乙個class寫乙個clone方法,而且隨著資料成員的增多,這個方法將越來越冗長,並且會由於資料成員的改變而引發錯誤(我曾經遇到過好幾次,由於class中增加了成員變數,而clone方法沒有及時更新,導致執行時錯誤。呵呵,這種錯誤還很難除錯)。現在你看到用serialization實現的好處了吧?是的,我們只要在基類中將clone方法宣告為virtual,並用serialization的方法實現之,然後保證基類和派生類都可以被serialize,上面所有的麻煩不都迎刃而解了嗎?
總結現代軟體專案中,無論何種專案都會或多或少地涉及到物件永續性的問題,.net也不例外,無論是windows form、asp.net,還是web services,都需要處理物件永續性。而serialization正是.net為應對這個問題而給出的解法。
物件序列化 反序列化
必須新增引用 using system.io using system.runtime.serialization using system.runtime.serialization.formatters.binary 方法 region 物件序列化 物件序列化 任意物件 字串 public st...
物件 序列化 反序列化
public class eventmessage 資訊提示類 型別1 操作日誌2 安全日誌 標題 內容 icon型別 url 執行script指令碼字串 需加 public static void messagebox int m type,string m title,string m body...
物件序列化
using system using system.io using system.diagnostics using system.reflection using system.runtime.serialization using system.runtime.serialization.fo...