似乎我可以序列化没有该接口的类,所以我不清楚它的目的。
4 回答
ISerializable
用于提供自定义二进制序列化,通常用于BinaryFormatter
(也可能用于远程处理)。没有它,它使用的字段可以是:
- 效率低下;如果存在仅在运行时用于提高效率的字段,但可以删除以进行序列化(例如,字典在序列化时可能看起来不同)
- 效率低下;即使对于需要的字段,它也需要包含许多额外的元数据
- 无效的; 如果有不能序列化的字段(比如事件委托,虽然可以标记
[NonSerialized]
) - 脆; 您的序列化现在绑定到字段名称 - 但字段意味着实现细节;另请参阅混淆、序列化和自动实现的属性
通过实现ISerializable
,您可以提供自己的二进制序列化机制。请注意,与 this 等效的 xml 是IXmlSerializable
, 由XmlSerializer
etc使用。
出于 DTO 目的,BinaryFormatter
应避免使用 xml(通过XmlSerializer
或DataContractSerializer
)或 json 之类的东西,以及诸如协议缓冲区之类的跨平台格式。
为了完整起见,protobuf-net 确实包含了钩子ISerializable
(允许您使用可移植的二进制格式而无需编写大量代码),但BinaryFormatter
无论如何都不是您的首选。
可以通过以下两种方式之一在 .NET 中对类进行序列化:
- 使用属性标记
SerializableAttribute
并装饰您不想序列化的所有字段NonSerialized
。(正如 Marc Gravell 指出的那样,BinaryFormatter
通常用于格式化ISerializable
对象的类会自动序列化所有字段,除非它们另有特别标记。) - 实现
ISerializable
完全自定义序列化的接口。
前者使用起来更简单,因为它只涉及用属性标记声明,但它的功能有限。后者允许更大的灵活性,但需要付出更多的努力来实施。您应该使用哪一个完全取决于上下文。
关于后者 ( ISerializable
) 及其用法,我从MSDN 页面中引用了该接口:
任何可能被序列化的类都必须用 SerializableAttribute 进行标记。如果一个类需要控制其序列化过程,可以实现ISerializable接口。Formatter 在序列化时调用 GetObjectData 并使用表示对象所需的所有数据填充提供的 SerializationInfo。Formatter 使用图中对象的类型创建一个 SerializationInfo。需要为自己发送代理的对象可以使用 SerializationInfo 上的 FullTypeName 和 AssemblyName 方法来更改传输的信息。
在类继承的情况下,可以序列化从实现 ISerializable 的基类派生的类。在这种情况下,派生类应在其 GetObjectData 实现中调用 GetObjectData 的基类实现。否则,来自基类的数据将不会被序列化。
使用ISerializable
您可以在对象中编写自定义方法以在进行二进制序列化时接管序列化,以与 BinaryFormatter 使用的默认方法不同的方式序列化对象。
换句话说,如果默认方法以不同于您希望它序列化的方式序列化您的对象,您可以实现 ISerializable 以获得完全控制。请注意,与 ISerializable 一起,您还应该实现一个自定义构造函数。
XmlSerialization 当然只会使用属性,ISerializable 与 XML 序列化无关。
感谢 Marc 和 Pop 的评论,我的第一个答案有点仓促。
为了使对象“可传输”,您必须对其进行序列化。例如,如果要使用 .NET Remoting 或 Web 服务传输对象数据,则必须提供序列化对象数据的方法,将对象实例减少为表示对象高保真表示的可传输格式。
然后,您还可以采用序列化表示,将其传输到另一个上下文,例如不同的机器,并重建您的原始对象。
实现ISerializable
接口时,类必须提供接口中包含的 GetObjectData 方法,以及专用于接受两个参数的专用构造函数:SerializationInfo 实例和 StreamingContext 实例。
如果您的类不需要对其对象状态进行细粒度控制,那么您可以只使用[Serializable]
属性。需要对序列化过程进行更多控制的类可以实现 ISerializable 接口。