【问题标题】:How to choose a field number when using protobuf-net inheritance?使用protobuf-net继承时如何选择字段号?
【发布时间】:2015-03-26 14:36:43
【问题描述】:

我正在使用 protobuf-net 序列化许多类型,其中一些是从基本类型继承的。我知道 Protocol Buffers 规范不支持继承,因此 protobuf-net 中的支持基本上是一种解决方法。

我没有使用 protobuf-net 属性,而是配置了自定义 RuntimeTypeModel,并使用了 AddAddSubType 方法。我不太明白我应该如何确定将哪些数字用于传递给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;
        }
    }
}

【问题讨论】:

    标签: c# inheritance protobuf-net


    【解决方案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
    • 啊,现在明白了!感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 2011-09-09
    • 1970-01-01
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    相关资源
    最近更新 更多