迁移到 protobuf-net(二进制)
protobuf-net 库是适用于 .NET 的基于协定的序列化程序,它使用二进制协议缓冲区serialization格式。 API 遵循典型的 .NET 模式,与 XmlSerializer
和 DataContractSerializer
大致相当。
在从 BinaryFormatter 迁移的过程中,需要注意 protobuf-net 的某些行为和功能,许多方案需要将特性应用于成员。
- 默认情况下,公共和非公共类型都是可序列化的,序列化程序需要无参数的构造函数。
- protobuf-net 要求使用
[ProtoContract]
特性注释每个可序列化类型;此特性可以选择指定SkipConstructor = true
属性,从而不需要任何特定的构造函数。 - 每个可序列化的非静态字段和属性都需要使用
[ProtoMember(int identifier)]
特性进行批注。 成员名称不会在数据中编码。 相反,用户必须选取一个正整数来标识该类型内必须唯一的每个成员。 - 必须通过具有已知子类型的每个类型上的
[ProtoInclude(...)]
特性显式声明继承。 - 默认情况下支持只读字段。
- 或者,构造函数模式可识别某些无特性类元组类型;若类型具有与所有已声明的公共成员匹配的参数的构造函数,则类型将被解释为元组,参数顺序将用于推断该成员的标识符。
- 强烈建议使用
protobuf-net.BuildTools
设计时,这能提供常见错误的编译时警告。
分步迁移
- 查找
BinaryFormatter
的所有用法。 - 确保 serialization 代码路径被测试覆盖,以便你可以验证你的更改并避免引入 bug。
- 安装
protobuf-net
包(或者protobuf-net.BuildTools
)。 - 查找正在通过
BinaryFormatter
进行序列化的所有类型。 - 对于可以修改的类型:
- 使用
[ProtoContract]
特性对所有标有[Serializable]
或实施ISerializable
接口的类型进行批注。 如果未向其他可能使用不同序列化程序(例如DataContractSerializer
)的应用公开这些类型(例如:你正在编写库),则可以可以删除[Serializable]
和ISerializable
注释。 - 对于派生类型,请将
[ProtoInclude(...)]
应用于其基类型(请参阅以下示例)。 - 对于声明任何接受参数的构造函数的每个类型,请添加无参数构造函数或在
[ProtoContract]
特性上指定SkipConstructor = true
。 写下注释,解释 protobuf-net 要求(以便没有人意外删除它)。 - 标记要通过
[ProtoMember(int identifier)]
序列化的所有成员(字段和属性)。 所有标识符在单个类型中必须是唯一的,但如果启用继承,则可以在子类型中重新使用相同的数字。
- 使用
- 对于无法修改的类型:
- 对于 .NET 本身提供的类型,可以使用
ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(Type type)
API 检查它们是否由 protobuf-net 本机支持。 - 可以创建专用数据传输对象 (DTO) 并相应地映射它们(可以使用隐式强制转换运算符)。
- 使用
RuntimeTypeModel
API 定义特性允许的所有内容。
- 对于 .NET 本身提供的类型,可以使用
- 将
BinaryFormatter
的用法替换为ProtoBuf.Serializer
。
-[Serializable]
+[ProtoContract]
+[ProtoInclude(2, typeof(Point2D))]
public class Point1D
{
+ [ProtoMember(1)]
public int X { get; set; }
}
-[Serializable]
+[ProtoContract]
public class Point2D : Point1D
{
+ [ProtoMember(2)]
public int Y { get; set; }
}