一個關於反序列化的小問題
大家都知道,我們具有三種定義可序列化類型的方式:在類型上應用SerializableAttribute特性;應用DataContractAttribute/DataMemberAttribute特性和實現ISerializable接口。當你通過繼承一個現有的類來定義你需要被序列化的類,如果這個父類實現了ISerializable接口,如果定義不當,就會出現反序列化的問題。而且這個我們可能經常都不注意。
首先,我想自定義一個字典類型MyDictionary,其Key和Value的類型分別為String和Object。最簡單的方式莫過於直接繼承Dictionary<string, object>。為了讓MyDictionary對象可序列化,我們在類型上麵應用了SerializableAttribute特性。MyDictionary定義如下:
1: [Serializable]
2: public class MyDictionary : Dictionary<string, object>
3: {
4: }
然後我通過下麵的代碼對MyDictionary對象進行序列化和反序列化,我直接采用的序列化器為BinaryFormatter。
1: static void Main(string[] args)
2: {
3: var dictionary = new MyDictionary();
4: dictionary.Add("001", "Foo");
5: dictionary.Add("002", "Bar");
6: dictionary.Add("003", "Baz");
7:
8: using (MemoryStream stream = new MemoryStream())
9: {
10: var formatter = new BinaryFormatter();
11: formatter.Serialize(stream, dictionary);
12: stream.Seek(0, 0);
13: dictionary = (MyDictionary)formatter.Deserialize(stream);
14: }
15:
16: foreach (var item in dictionary)
17: {
18: Console.WriteLine("{0}: {1}", item.Key, item.Value);
19: }
20: }
現在我們運行這段代碼,在進行但序列化的時候出現如下SerialiationException的異常,錯誤消息提示找不到構造函數。
通過上麵的截圖,我們可以看到具體的錯誤消息:“”,對於這個消息,我們第一個反應是在反序列化的時候找不到默認(無參)的構造函數。但是再看MyDictionary的定義,我們不曾定義任何構造函數,意味著它具有一個默認(無參)構造函數。
實際上,這裏並不是找不到默認(無參)構造函數,而是找不到一個具有特殊參數列表的構造函數。該構造函數接收兩個參數,類型分別是:SerializationInfo和StreamingContext。所以我們的解決方案很簡單,就是加上這麼一個構造函數。為此我們從新定義MyDictionary。
1: [Serializable]
2: public class MyDictionary : Dictionary<string, object>
3: {
4: public MyDictionary() { }
5: protected MyDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
6: }
從新運行我們的程序,你就會得到想要的輸出結果:
1: 001: Foo
2: 002: Bar
3: 003: Baz
如果一個類型實現了ISerializable接口(Dictionary<TKey, TValue>就實現了這個接口),你就應該定義如上一個構造函數。這算是一個約定,但是當你繼承某個類型的時候,你往往會忘記這個約定。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-27 11:04:18