序列化

注释

此内容由 Pearson Education, Inc. 的许可从 框架设计指南:可重用 .NET 库的约定、习惯和模式(第 2 版)重新打印。 该版于2008年出版,此后该书已于 第三版全面修订。 此页上的一些信息可能已过期。

序列化是将对象转换为可以轻松持久保存或传输的格式的过程。 例如,可以序列化对象,使用 HTTP 通过 Internet 传输对象,并在目标计算机上反序列化它。

.NET Framework 提供针对各种序列化方案优化的三种主要序列化技术。 下表列出了这些技术和与这些技术相关的主要框架类型。

技术名称 主要类型 方案
数据协定序列化 DataContractAttribute
DataMemberAttribute
DataContractSerializer
NetDataContractSerializer
DataContractJsonSerializer
ISerializable
一般持久性
Web 服务
JSON(JavaScript 对象表示法)
XML 序列化 XmlSerializer 对 XML 形状具有完全控制权的 XML 格式
运行时序列化(二进制和 SOAP) SerializableAttribute
ISerializable
BinaryFormatter
SoapFormatter
.NET 远程处理

✔️ 设计新类型时,请考虑序列化。

选择要支持的正确序列化技术

✔️ 如果可能需要在 Web 服务中持久保存或使用类型实例,请考虑支持数据协定序列化。

✔️ 如果需要对序列化类型时生成的 XML 格式具有更多控制,则应考虑改为支持 XML 序列化,或者在支持数据协定序列化之外还支持 XML 序列化。

在某些互作性方案中,可能需要使用数据协定序列化不支持的 XML 构造,例如生成 XML 属性。

✔️ 如果类型的实例需要跨越 .NET 远程处理边界,请考虑支持运行时序列化。

❌ 避免仅出于常规持久性原因支持运行时序列化或 XML 序列化。 请改用数据协定序列化。

支持数据协定序列化

类型可以通过将 DataContractAttribute 应用于类型以及 DataMemberAttribute 应用于类型的成员(字段和属性)来支持数据协定序列化。

✔️ 如果可以在部分信任模式下使用类型,则考虑将类型的数据成员标记为公共的。

在完全信任中,数据协定序列化程序可以序列化和反序列化非公共类型和成员,但只能在部分信任中序列化和反序列化公共成员。

✔️ 请为具有 DataMemberAttribute 的所有属性编写 getter 和 setter 操作。 数据契约序列化程序需要同时具有取值器和赋值器,才能将类型视为可序列化。 (在 .NET Framework 3.5 SP1 中,某些集合属性可以为仅限获取属性。)如果不会在部分信任模式下使用类型,则这两个属性访问器中的一个或两个都可以是非公共的。

✔️ 考虑使用序列化回调函数来初始化反序列化后的实例。

反序列化对象时,不会调用构造函数。 (规则有例外。反序列化期间会调用用 CollectionDataContractAttribute 标记的集合的构造函数。)因此,在正常构造期间执行的任何逻辑都需要作为序列化回调之一实现。

OnDeserializedAttribute 是最常用的回调属性。 家庭中的其他属性是 OnDeserializingAttributeOnSerializingAttributeOnSerializedAttribute。 这些属性可分别用来标记在反序列化之前、序列化之前以及序列化之后执行的回调。

✔️ 请考虑使用 KnownTypeAttribute 指示反序列化复杂对象图时应使用的具体类型。

✔️ 创建或更改可序列化类型时,请考虑向后和向前兼容性。

请记住,类型的未来版本的序列化流可反序列化到类型的当前版本,反之亦然。

请确保了解数据成员(即使是私有成员和内部成员)无法在类型的未来版本中更改其名称、类型,甚至不能更改其顺序,除非特别小心地使用显式参数来保留协定的数据协定属性。

对可序列化类型进行更改时测试序列化的兼容性。 尝试将新版本反序列化为旧版本,以及将旧版本反序列化为新版本。

✔️ 考虑实现 IExtensibleDataObject 以允许在不同版本的类型之间进行往返。

该接口允许序列化程序确保在往返过程中不会丢失任何数据。 该 IExtensibleDataObject.ExtensionData 属性用于存储当前版本未知类型的未来版本中的任何数据,因此它无法将其存储在其数据成员中。 当当前版本随后序列化并反序列化为将来的版本时,序列化流中将提供其他数据。

支持 XML 序列化

数据协定序列化是 .NET Framework 中的主要(默认)序列化技术,但存在数据协定序列化不支持的序列化方案。 例如,它不让你完全控制序列化程序生成或使用的 XML 的形状。 如果需要这种精细控制,则必须使用 XML 序列化,并且需要设计类型以支持此序列化技术。

❌ 避免专门为 XML 序列化设计类型,除非有非常强烈的原因来控制生成的 XML 形状。 此序列化技术已被上一部分讨论的数据协定序列化取代。

✔️ 如果通过应用 XML 序列化属性所提供的对于序列化 XML 的形状的控制还无法满足你的需要,则可考虑实现 IXmlSerializable 接口。 接口的两个方法,ReadXmlWriteXml,允许您完全控制序列化的 XML 流。 还可以通过应用该 XmlSchemaProviderAttribute类型来控制为类型生成的 XML 架构。

支持运行时序列化

运行时序列化是 .NET 远程处理使用的技术。 如果认为类型将使用 .NET 远程处理进行传输,则需要确保它们支持运行时序列化。

可以通过应用 SerializableAttribute更高级的方案来提供对运行时序列化的基本支持,包括实现简单的运行时可序列化模式(实现 ISerializable 并提供序列化构造函数)。

✔️ 如果类型将用于 .NET 远程处理,请考虑支持运行时序列化。 例如,System.AddIn 命名空间使用 .NET 远程处理,因此 System.AddIn 加载项之间交换的所有类型都需要支持运行时序列化。

✔️ 如果想要完全控制序列化过程,请考虑实现运行时可序列化模式。 例如,如果您需要在对数据进行序列化或反序列化时转换数据。

模式非常简单。 只需实现 ISerializable 接口并提供在反序列化对象时使用的特殊构造函数。

✔️ 请务必保护序列化构造函数,并提供完全按照此处示例中所示类型化和命名的两个参数。

[Serializable]
public class Person : ISerializable
{
    protected Person(SerializationInfo info, StreamingContext context)
    {
        // ...
    }
}

✔️ 请务必显式实现 ISerializable 成员。

✔️ 请务必将链接要求应用到 ISerializable.GetObjectData 实现。 这可确保只有完全受信任的核心和运行时序列化程序才能访问该成员。

部分内容 © 2005, 2009 Microsoft 公司。 保留所有权利。

获得皮尔逊教育公司许可后重印自 框架设计准则:可重用 .NET 库的约定、习惯和模式 ,由 Krzysztof Cwalina 和 Brad Abrams 编写,并作为微软 Windows 开发系列中的出版物之一,于 2008 年 10 月 22 日由 Addison-Wesley Professional 出版。

另请参阅