使用protobuf-net继承时如何选择字段号?
Posted
技术标签:
【中文标题】使用protobuf-net继承时如何选择字段号?【英文标题】:How to choose a field number when using protobuf-net inheritance? 【发布时间】:2015-03-26 14:36:43 【问题描述】:我正在使用 protobuf-net 序列化许多类型,其中一些是从基本类型继承的。我知道 Protocol Buffers 规范不支持继承,因此 protobuf-net 中的支持基本上是一种解决方法。
我没有使用 protobuf-net 属性,而是配置了自定义 RuntimeTypeModel
,并使用了 Add
和 AddSubType
方法。我不太明白我应该如何确定将哪些数字用于传递给AddSubType
方法的字段编号(也就是将在ProtoInclude
属性中使用的数字)。
This SO question 和其他几个类似的并没有真正描述如何选择字段编号,实际上我已经看到了许多不同的变化:4 和 5; 7 & 8; 101 & 102 & 103; 20; 500;等等。显然他们被选中是为了不互相冲突,但是如何他们是被选中的?什么决定了从哪个数字开始?
以下代码是一个人为的示例,但它确实符合我的层次结构(具有两个派生子类型的基本 Event
类型)。
using System;
using System.Collections.Generic;
using ProtoBuf.Meta;
namespace Test
public sealed class History
public History()
Events = new List<Event>();
public ICollection<Event> Events get; private set;
public enum EventType
ConcertStarted, ConcertFinished, SongPlayed
public class Event
public EventType Type get; set;
public DateTimeOffset Timestamp get; set;
public sealed class Concert : Event
public string Location get; set;
public sealed class Song : Event
public string Name get; set;
public static class ModelFactory
public static RuntimeTypeModel CreateModel()
RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(DateTimeOffset), applyDefaultBehaviour: false)
.SetSurrogate(typeof(DateTimeOffsetSurrogate));
model.Add(typeof(History), applyDefaultBehaviour: false)
.Add("Events");
model.Add(typeof(Concert), applyDefaultBehaviour: false)
.Add("Location");
model.Add(typeof(Song), applyDefaultBehaviour: false)
.Add("Name");
model.Add(typeof(Event), applyDefaultBehaviour: false)
.Add("Type", "Timestamp")
.AddSubType(???, typeof(Concert))
.AddSubType(???, typeof(Song));
return model;
【问题讨论】:
【参考方案1】:没有其他要求:
它们必须是正整数 他们不能冲突 它们必须可靠地重复(重要的是,无论您重新启动应用程序多少次,即使您添加了其他类型等,子类型和数字都必须匹配)除此之外:没关系。留出空隙可能会更容易向父类型添加其他字段而不会意外产生冲突,但是:较小的字段编号序列化成本更低,因此如果可能:更喜欢小数字
【讨论】:
当您说“它们不能冲突”时,我是否说子类型字段编号必须大于基类型中的最高字段编号?那么如果基类型有字段号 1 和 2,那么子类型的字段号必须大于 2 吗?而且您是否还说子类型字段编号必须都是唯一的?例如,如果我有从 A 派生的类型 A1 和 A2,从 B 派生的 B1 和 B2,那么 A1、A2、B1 和 B2 必须都有不同的子类型字段编号? @StevenRands 不,只是不同;子类型编号可以是 1、3、5,字段可以是 2、4、6 - 当然,这会令人困惑。对于类型 X,X 的 字段 和 X 的 立即子类型 共享一个 protobuf 范围,因此这些数字不能重叠 - 但是,如果 Y 是X 的子类型,X 和 Y 之间对字段编号没有限制 - 它们是完全独立的。所以 X 可以有字段 1,2,3(并且 Y 作为带有标记 4 的子类型),并且 Y 可以也有字段 1,2,3,4 啊,现在明白了!感谢您的澄清。以上是关于使用protobuf-net继承时如何选择字段号?的主要内容,如果未能解决你的问题,请参考以下文章
不支持 Protobuf-NET IExtensible 继承的解决方法
如何停止使用 Protobuf-Net 继承,直接使用继承类?
如何通过 ProtoBuf-net 使用 DateTimeKind 选项序列化 DateTime 字段