大家都知道,我们具有三种定义可序列化类型的方式:在类型上应用SerializableAttribute特性;应用DataContractAttribute/DataMemberAttribute特性和实现ISerializable接口。当你通过继承一个现有的类来定义你需要被序列化的类,如果这个父类实现了ISerializable接口,如果定义不当,就会出现反序列化的问题。而且这个我们可能经常都不注意。
一、问题重现
首先,我想自定义一个字典类型MyDictionary,其Key和Value的类型分别为String和Object。最简单的方式莫过于直接继承Dictionarystring, object。为了让MyDictionary对象可序列化,我们在类型上面应用了SerializableAttribute特性。MyDictionary定义如下:
1:[Serializable]
2:publicclassMyDictionary:Dictionarystring,object
3:{
4:}
然后我通过下面的代码对MyDictionary对象进行序列化和反序列化,我直接采用的序列化器为BinaryFormatter。
1:staticvoidMain(string[]args)
2:{
3:vardictionary=newMyDictionary();
4:dictionary.Add(001,Foo);
5:dictionary.Add(002,Bar);
6:dictionary.Add(003,Baz);
7:
8:using(MemoryStreamstream=newMemoryStream())
9:{
10:varformatter=newBinaryFormatter();
11:formatter.Serialize(stream,dictionary);
12:stream.Seek(0,0);
13:dictionary=(MyDictionary)formatter.Deserialize(stream);
14:}
15:
16:foreach(varitemindictionary)
17:{
18:Console.WriteLine({0}:{1},item.Key,item.Value);
19:}
20:}
现在我们运行这段代码,在进行但序列化的时候出现如下SerialiationException的异常,错误消息提示找不到构造函数。
二、解决问题
通过上面的截图,我们可以看到具体的错误消息:“The constructor to deserialize an object of type 'DeserializationIssue.MyDictionary' was not found.”,对于这个消息,我们第一个反应是在反序列化的时候找不到默认(无参)的构造函数。但是再看MyDictionary的定义,我们不曾定义任何构造函数,意味着它具有一个默认(无参)构造函数。
实际上,这里并不是找不到默认(无参)构造函数,而是找不到一个具有特殊参数列表的构造函数。该构造函数接收两个参数,类型分别是:SerializationInfo和StreamingContext。所以我们的解决方案很简单,就是加上这么一个构造函数。为此我们从新定义MyDictionary。
1:[Serializable]
2:publicclassMyDictionary:Dictionarystring,object
3:{
4:publicMyDictionary(){}
5:protectedMyDictionary(SerializationInfoinfo,StreamingContextcontext):base(info,context){}
6:}
从新运行我们的程序,你就会得到想要的输出结果:
1:001:Foo
2:002:Bar
3:003:Baz
如果一个类型实现了ISerializable接口(DictionaryTKey, TValue就实现了这个接口),你就应该定义如上一个构造函数。这算是一个约定,但是当你继承某个类型的时候,你往往会忘记这个约定。