ISerializable 接口的意义何在?

Posted

技术标签:

【中文标题】ISerializable 接口的意义何在?【英文标题】:What is the point of the ISerializable interface? 【发布时间】:2010-10-23 02:19:35 【问题描述】:

似乎我可以序列化没有该接口的类,所以我不清楚它的目的。

【问题讨论】:

ISerializable 是一个接口,而不是一个属性。您的问题是关于接口 ISerializable 还是 SerializableAttribute 类? @Martin,在问题本身中,他只提到了属性。所以我想问题不在于界面。如果有人可以编辑问题标题? 我和 Martin 一样对这个问题感到困惑,但我认为这是关于界面的,因为他特别提到了 ISerializable。 @mek:如果您实际上是指属性,请让我知道/编辑问题。 对问题的错误编辑,它是关于属性......而不是界面。他用了两次属性这个词 【参考方案1】:

ISerializable 用于提供自定义二进制序列化,通常用于BinaryFormatter(也可能用于远程处理)。没有它,它使用的字段可以是:

效率低下;如果存在仅在运行时用于提高效率的字段,但可以删除以进行序列化(例如,字典在序列化时可能看起来不同) 效率低下;即使对于需要的字段,它也需要包含许多额外的元数据 无效;如果存在无法序列化的字段(例如事件委托,尽管它们可以标记为[NonSerialized]) 易碎;您的序列化现在绑定到 field 名称 - 但字段意味着实现细节;另见Obfuscation, serialization and automatically implemented properties

通过实现ISerializable,您可以提供自己的二进制序列化机制。请注意,与 IXmlSerializable 等效的 xml 是 XmlSerializer 等所使用的。

出于 DTO 目的,应避免使用 BinaryFormatter - xml(通过 XmlSerializerDataContractSerializer)或 json 之类的东西很好,协议缓冲区之类的跨平台格式也是如此。

为了完整起见,protobuf-net 确实包含ISerializable 的挂钩(允许您使用可移植的二进制格式而无需编写大量代码),但BinaryFormatter 无论如何都不是您的首选。

【讨论】:

很好的答案!只是标记,如果序列化类型标有“System.Serializable”属性,DataContractSerializer 也可以使用 ISerializable 进行自定义 XML 序列化(参见 answer 中的 TestClass2)【参考方案2】:

可以通过以下两种方式之一在 .NET 中对类进行序列化:

    SerializableAttribute 标记类,并用NonSerialized 属性装饰您想要序列化的所有字段。 (正如 Marc Gravell 所指出的,BinaryFormatter 是通常用于格式化 ISerializable 对象的类,它会自动序列化所有字段,除非它们另有特别标记。) 实现ISerializable 接口以实现完全自定义的序列化。

前者使用起来更简单,因为它只涉及用属性标记声明,但它的功能有限。后者允许更大的灵活性,但需要付出更多的努力来实施。您应该使用哪一个完全取决于上下文。

关于后者 (ISerializable) 及其用法,我已经引用了MSDN page 的接口:

任何可能被序列化的类 必须标有 可序列化属性。如果一个班级 需要控制它的序列化 过程中,它可以实现 ISerializable 接口。格式化程序 调用 GetObjectData 在 序列化时间并填充 提供了所有的 SerializationInfo 表示所需的数据 目的。格式化程序创建一个 SerializationInfo 的类型为 图中的对象。需要的对象 为自己发送代理可以使用 FullTypeName 和 AssemblyName SerializationInfo 上要更改的方法 传输的信息。

在类继承的情况下,它 可以序列化一个类 派生自一个基类 实现 ISerializable。在这个 情况下,派生类应该调用 的基类实现 GetObjectData 里面 GetObjectData 的实现。 否则,来自基础的数据 类不会被序列化。

【讨论】:

Re point 1:BinaryFormatter(ISerializable的主要消费者)不关心属性,默认使用所有字段(需要选择退出) (我修复了 NonSerialized 属性名称;希望你不要介意。我在原来的帖子中也弄错了...... ;-p) 当然,序列化类的第三种方式是使用XML Serializer,第四种方式是使用Data Contract Serializer。 @Marc:当然不是。 :) 正如你所看到的,我对关于序列化的属性名称有点模糊。无论如何,你的答案更完整,所以嗯。【参考方案3】:

使用ISerializable,您可以在对象中编写自定义方法,以便在进行二进制序列化时接管序列化,以不同于 BinaryFormatter 使用的默认方法的方式序列化对象。

换句话说,如果默认方法以不同于您希望它序列化的方式序列化您的对象,您可以实现 ISerializable 以获得完全控制。请注意,与 ISerializable 一起,您还应该实现一个自定义构造函数。

XmlSerialization 当然只会使用属性,ISerializable 与 XML 序列化无关。

感谢 Marc 和 Pop 的 cmets,我的第一个答案有点草率。

【讨论】:

这个答案不正确; ISerializable 与 BinaryFormatter 相关; “public with get/set”与 XmlSerializer 有关——两者是非常不同的野兽,具有完全不同的规则。 这仅适用于 XML 序列化,二进制序列化序列化对象(私有或公共)的字段,而不是通过属性读取的对象的外部图像。这是 ISerializable 最有用的地方。【参考方案4】:

为了使对象“可传输”,您必须对其进行序列化。例如,如果您想使用 .NET Remoting 或 Web 服务传输对象数据,则必须提供序列化对象数据的方法,将对象实例减少为表示对象高保真表示的可传输格式。

然后,您还可以获取序列化表示,将其传输到另一个上下文(例如不同的机器),然后重建您的原始对象。

当实现ISerializable 接口时,一个类必须提供接口中包含的GetObjectData 方法,以及一个专门接受两个参数的专用构造函数:一个SerializationInfo 实例和一个StreamingContext 实例。

如果您的类不需要对其对象状态进行细粒度控制,那么您可以只使用[Serializable] 属性。需要对序列化过程进行更多控制的类可以实现 ISerializable 接口。

【讨论】:

有中途点吗?我很想对某些领域进行一些类似于 ISerializable 的控制,但对于其他领域,我会退回到通常的机制。 是与否,到了一半。您可以在要序列化的所有字段/属性上尝试“DataContractAttribute”和“DataMemberAttribute”,在所有不想序列化的字段/属性上尝试“IgnoreDataMemberAttribute”。还有一些属性可用于预处理和后处理(反)序列化的方法,例如“OnSerializingAttribute”和“OnDeserializedAttribute”。我用它执行了一些黑魔法:序列化一个对象结构,该结构使用动态加载的 dll 中的类,并序列化这些 dll,以便将它们重新加载以再次加载所有内容。为此,我去了 .dll 地狱。

以上是关于ISerializable 接口的意义何在?的主要内容,如果未能解决你的问题,请参考以下文章

java中标记接口的意义何在?为啥没有它们我们就不能继续?

noreturn 的意义何在?

严格声明的意义何在?

-primitiveValueForKey: 的意义何在?

Kotlin 中使用函数的意义何在

Windows 上 Mono 的意义何在