Protobuf-net:如何在继承类中添加同字段并保持向后兼容性
如何在保持向后兼容的前提下给House类添加Pincode属性?
先明确现有基于ProtoBuf的类结构:
基类Address
[ProtoContract] [ProtoInclude(10, typeof(Store))] [ProtoInclude(11, typeof(House))] public abstract class Address { [ProtoMember(1)] Id ; [ProtoMember(2)] string Country; }
子类Store
[ProtoContract] public class Store: Address { [ProtoMember(1)] int StoreUniqueid; [ProtoMember(2)] string StoreUniqueValue; [ProtoMember(3)] string Pincode; }
子类House
[ProtoContract] public class House : Address { [ProtoMember(1)] int HouseArea; }
现在要给House类添加Store中已有的Pincode属性,同时保证向后兼容性,以下是对两种方案的分析和最优选择:
方案1分析:将Pincode移至基类Address
这种做法会直接破坏向后兼容性,风险极高:
- 旧版本序列化的Store实例中,Pincode是作为子类Store的字段(编号3)存储的,移到基类后,无论给基类的Pincode分配哪个编号,都会和旧数据的字段归属逻辑冲突,导致反序列化时数据读取混乱。
- 移除Store类中的Pincode后,旧版本Store序列化的数据在新版本中反序列化时,Pincode值会直接丢失。
方案2分析:在House类中新增同名Pincode属性
这是完全可行且安全的方案,具体代码如下:
[ProtoContract] public class House: Address { [ProtoMember(1)] int HouseArea; [ProtoMember(2)] string Pincode; }
ProtoBuf的序列化机制基于字段编号而非字段名,只要House类中新增的Pincode字段编号(此处为2)没有和同类现有字段(HouseArea是1)冲突,同时不干扰Store类的字段编号(Store的Pincode是3),就不会有兼容性问题:
- 旧版本House实例反序列化到新版本时,Pincode会被设为对应类型的默认值(string类型为null),不会抛出异常,也不影响现有数据。
- 新版本House实例序列化后,旧版本House类反序列化时会自动忽略这个新增的字段编号2,不会出现解析错误。
- Store类的Pincode字段完全不受影响,新旧版本的Store数据都能正常序列化、反序列化。
额外注意事项
- 确保新增字段的编号在当前类中唯一,不要和同类其他字段的
ProtoMember编号重复。 - 如果后续需要统一Pincode的处理逻辑,可以在基类中新增虚拟属性,让Store和House各自实现,但这一步不是必须的,且不会影响现有兼容性。
内容的提问来源于stack exchange,提问作者Swaroop
相关产品推荐
相关产品推荐

