zoukankan      html  css  js  c++  java
  • 一个关于反序列化的小问题

    大家都知道,我们具有三种定义可序列化类型的方式:在类型上应用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的异常,错误消息提示找不到构造函数。

    image

    二、解决问题

    通过上面的截图,我们可以看到具体的错误消息:“The constructor to deserialize an object of type 'DeserializationIssue.MyDictionary' was not found.”,对于这个消息,我们第一个反应是在反序列化的时候找不到默认(无参)的构造函数。但是再看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>就实现了这个接口),你就应该定义如上一个构造函数。这算是一个约定,但是当你继承某个类型的时候,你往往会忘记这个约定。

  • 相关阅读:
    【转】svn冲突问题详解 SVN版本冲突解决详解
    【转】Mysql解决The total number of locks exceeds the lock table size错误
    【转】iOS中修改AVPlayer的请求头信息
    【转】AJAX请求和普通HTTP请求区别
    【转】怎么给javascript + div编辑框光标位置插入表情文字等?
    【转】iOS开发笔记--识别单击还是双击
    【转】Android hdpi ldpi mdpi xhdpi xxhdpi适配详解
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
  • 原文地址:https://www.cnblogs.com/artech/p/SerializationIssue.html
Copyright © 2011-2022 走看看