协议缓冲区如何处理类型版本控制?
例如,当我需要随时间更改类型定义时?就像添加和删除字段一样。
答案 0 :(得分:22)
谷歌设计的protobuf对版本化非常宽容:
但是:
一般来说,虽然 - 它只是工作,你不需要担心版本控制。
答案 1 :(得分:5)
我知道这是一个老问题,但最近我遇到了这个问题。我绕过它的方式是使用外观和运行时决定序列化。通过这种方式,我可以将字段弃用/升级为新类型,旧消息和新消息可以正常处理它。
我正在使用Marc Gravell的protobuf.net(v2.3.5)和C#,但外墙理论适用于任何语言和Google原始的protobuf实现。
我的旧类有一个DateTime的时间戳,我想改变它以包含“Kind”(一个.NET时代错误)。有效地添加它意味着它被序列化为9个字节而不是8个字节,这将是一个破坏序列化的变化!
[ProtoMember(3, Name = "Timestamp")]
public DateTime Timestamp { get; set; }
protobuf的基础是永远不要改变原型!我想阅读旧的序列化二进制文件,这意味着“3”就在这里。
所以,
我重命名了旧属性并将其设为私有(是的,它仍然可以通过反射魔法反序列化),但我的API不再显示它可用!
[ProtoMember(3, Name = "Timestamp-v1")]
private DateTime __Timestamp_v1 = DateTime.MinValue;
我创建了一个新的Timestamp属性,带有一个新的proto id,并包含了DateTime.Kind
[ProtoMember(30002, Name = "Timestamp", DataFormat = ProtoBuf.DataFormat.WellKnown)]
public DateTime Timestamp { get; set; }
我添加了一个“AfterDeserialization”方法来更新我们的新时间,如果是旧消息
[ProtoAfterDeserialization]
private void AfterDeserialization()
{
//V2 Timestamp includes a "kind" - we will stop using __Timestamp - so keep it up to date
if (__Timestamp_v1 != DateTime.MinValue)
{
//Assume the timestamp was in UTC - as it was...
Timestamp = new DateTime(__Timestamp_v1.Ticks, DateTimeKind.Utc) //This is for old messages - we'll update our V2 timestamp...
}
}
现在,我正确地序列化/反序列化旧消息和新消息,我的Timestamp现在包含DateTime.Kind!什么都没破。
然而,这确实意味着BOTH字段将在所有新消息中继续存在。因此,最后一步是使用运行时序列化决策来排除旧的时间戳(请注意,如果使用protobuf的必需属性,这将无法工作!!!)
bool ShouldSerialize__Timestamp_v1()
{
return __Timestamp_v1 != DateTime.MinValue;
}
就是这样。如果有人想要的话,我有一个很好的单元测试,它可以从头到尾完成...
我知道我的方法依赖于.NET魔法,但我认为这个概念可以翻译成其他语言....