序列化/反序列化和非默认构造函数

考虑这个课程:

[Persistable] public sealed class FileMoveTask : TaskBase { [PersistMember] public string SourceFilePath { get; private set;} [PersistMember] public string DestFilePath { get; private set;} public FileMoveTask(string srcpath, string dstpath) { this.SourceFilePath = srcpath; this.DestFilePath = dstpath; //possibly other IMPORTANT initializations } //code } 

我可以通过使用属性PersistMember序列化所有成员来持久保存此类的对象。 但是在反序列化过程中我遇到了一些问题(设计问题)。 特别是,问题在于构造函数中可能存在的“可能的其他重要初始化” ,并且程序员可能决定不会使少数成员可持久化(即不PersistMember添加PersistMember )可能因为这没有意义。

在这种情况下,我如何将对象反序列化为完全相同的状态? 我想,这个问题归结为:我如何调用非默认构造函数,将相同的参数传递给它,之前传递过? 有没有办法做到这一点? 我们可以制定一些可以由编译器强制执行的规则(一种元编程)吗? 构造函数属性可以在这帮助吗?

你可以用两种方式解决这个问题。 使用约定优于配置(将构造函数参数命名为属性,并且不包含默认构造函数):

 [Persistable] public sealed class FileMoveTask : TaskBase { [PersistMember] public string SourceFilePath { get; private set;} [PersistMember] public string DestFilePath { get; private set;} public FileMoveTask(string sourceFilePath, string destFilePath) { this.SourceFilePath = srcpath; this.DestFilePath = dstpath; //possibly other IMPORTANT initializations } //code } 

使用您的属性显式标记构造函数参数,并搜索已标记的构造函数:

 [Persistable] public sealed class FileMoveTask : TaskBase { [PersistMember] public string SourceFilePath { get; private set;} [PersistMember] public string DestFilePath { get; private set;} public FileMoveTask([PersistMember("SourceFilePath")]string srcpath, [PersistMember("DestFilePath")]string dstpath) { this.SourceFilePath = srcpath; this.DestFilePath = dstpath; //possibly other IMPORTANT initializations } //code } 

属性或参数名称不用于知道要设置的属性,而是用于了解在调用构造函数时要使用的序列化数据中的哪些信息。

解决此问题的最简单方法是使用现有的众所周知的技术。 例如,看看.NET框架中使用的其他序列化机制(你会注意到巨大的多样性)。

例如,在BinaryFormatter中 , SoapFormatter和DataContractSerializer使用以下技术对反序列化对象:

  1. 通过调用FormatterServices.GetUnitializedObject获取“原始”对象
  2. 在构造对象上调用单独的预序列化方法(通过检查标记为OnSerializingAttribute的方法)。
  3. 反序列化对象的状态(通过检查适当的属性来了解序列化程序应该跳过哪些字段以及它应该反序列化的字段)。
  4. 在反序列化对象上调用post-serialization方法(通过检查标记为OnSerializedAttribute的方法)。

另一方面, XmlSerializer使用绝对不同的算法:它需要无参数构造函数,应该用作“预序列化”和“序列化后”步骤。

所以我的观点是它完全取决于序列化器的类型和实现。 并且仍需要序列化程序的作者和序列化程序的消费者的一些心理努力。

所以我强烈建议使用现有技术之一,但不要发明轮子(比如添加一些其他自定义属性来恢复对象的状态)。 您甚至可以使用现有属性来简化从.NET序列化工具到自定义序列化机制的迁移(以及使用其他属性,如NonSerializableAttrubite )。