本鱼拟成立工作室承接项目开发/软件定制/云设施开发运维/办公设备技术支持等,如您有相关需求,欢迎来询 | ::博客文章推荐::

如果解决在使用二进制序列化时对实体内其它对象的引用依赖

: DOT.NET 木魚 6177℃ 0评论

目前在做一个编辑器,编辑过程中有个保存编辑内容的实体类。因为内容比较复杂,为了防止意外的问题在保存的时候使用二进制序列化,但是这时就遇到一个问题,因为编辑需要这个实体类里面是有事件的,并且在编辑过程中这个事件已经被绑定到了用户控件。由于二进制序列化是精确还原对象的,所以尝试对这个实体类进行序列化的时候发生了问题:绑定了事件的用户控件是不可序列化的。

实体类部分代码如下:

   1:  [Serializable]
   2:  public class LabelItem
   3:  {
   4:      public event EventHandler TitleChanged;
   5:      public event EventHandler TextChanged;
   6:   
   7:      public event EventHandler PicChanged;
   8:   
   9:      //....其它代码一起实体类内容
  10:  }
  11:   

 

这个类在使用二进制序列化的时候,有可能你会遇到类似下面的错误:

serialize_object_ref

错误信息为:
未处理的“System.Runtime.Serialization.SerializationException”类型的异常出现在 mscorlib.dll 中。

其他信息: 程序集“FSLib.OII.Editor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”中的类型“FSLib.OII.Editor.Controls.LabelEditItem”未标记为可序列化。

究其原因,是因为LabelEditItem在编辑过程中绑定了LabelItem的几个事件以便于同步更新所有数据。但是它本身是个用户控件所以无法被序列化(当然我没加可序列化标记,但是我估计就算加了也是徒然)。

对于现在的问题,解决方案有两个:
1.抽象出实体类,去掉里面的事件等其它内容。对于事件等,则在继承的子类中编写。
2.在序列化的时候对它动手脚。

不要意思我很懒,所以第一个方法被排除了。因为这里面涉及了太多的类的改写动作,显然得不偿失。那下面从第二个解决方法下手(这里是事件,如果有其它导致无法正常序列化的内容时也可参考)。

用过序列化的同学都知道,序列化都有个 NonSerialized 的属性,这个属性用于标记在序列化过程中被忽略的字段。但是这个标记仅对字段起效,对于事件啊属性啊统统无效。经过测试,发现当事件没有被绑定(TitleChanged==null)的时候不会引发异常,那么我们就在这里下手脚吧。

对于序列化,有两个我们会用到的属性:OnSerializingOnSerialized ,分别在开始序列化的时候、序列化完成的时候标记被调用。当然加这个属性的函数是有要求的,这个函数接受一个类型为 StreamingContext 的参数。与此相对应的,反序列化也会有对应的两步操作。
也许解决方案所有的同学都已经知道了:开始序列化的时候,将所有的事件都保存到已标记为NonSerialized 的字段中再清空事件;序列化完成后再还原事件,这样只要加两个函数,那所有的代码就都不用改了。
在本例中,代码如下(反序列化后,事件需要重新绑定的当然):

   1:  public class LabelItem
   2:  {
   3:      public event EventHandler TitleChanged;
   4:      public event EventHandler TextChanged;
   5:   
   6:      public event EventHandler PicChanged;
   7:   
   8:      [NonSerialized]
   9:      EventHandler _titleChanged;
  10:   
  11:      [NonSerialized]
  12:      EventHandler _textChanged;
  13:   
  14:      [NonSerialized]
  15:      EventHandler _picChanged;
  16:   
  17:      [OnSerializing]
  18:      void BeforeSerialize(StreamingContext ctx)
  19:      {
  20:          _titleChanged = _textChanged = _picChanged = null;
  21:   
  22:          if (TitleChanged != null) { _titleChanged = TitleChanged; TitleChanged = null; }
  23:          if (TextChanged != null) { _textChanged = TextChanged; TextChanged = null; }
  24:          if (PicChanged != null) { _picChanged = PicChanged; PicChanged = null; }
  25:      }
  26:   
  27:      [OnSerialized]
  28:      void AfterSerialize(StreamingContext ctx)
  29:      {
  30:          if (_titleChanged != null) TitleChanged = _titleChanged;
  31:          if (_textChanged != null) TextChanged = _titleChanged;
  32:          if (_picChanged != null) PicChanged = _titleChanged;
  33:      }
  34:  }

问题到这里已经解决了,但是喜欢举一反三的我们是否会联想到其它的用途呢?

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址