协议缓冲区和枚举组合

本文关键字:组合 枚举 缓冲区 协议 | 更新日期: 2023-09-27 18:29:41

这是我的原型文件:

message MSG {
  required MsgCodes MsgCode = 1;
  optional int64 Serial = 2;        // Unique ID number for this person.
  required int32 From = 3;  
  required int32 To = 4;  
  //bla bla...
        enum MsgCodes
        {
            MSG = 1;
            FILE = 2;
            APPROVE=4;
            ACK=8;
            ERROR_SENDING=16;
            WORLD=32;
        }
}

在我的C#中,我试图:

 msg = msg.ToBuilder().SetMsgCode(msg.MsgCode | MSG.Types.MsgCodes.ACK | MSG.Types.MsgCodes.APPROVE).Build();
 SendToJava(msg);

但是JAVA告诉我:缺少MsgCode(它是required

删除组合-是否解决问题

但我需要指定组合

问题

我该如何解决?

nb:

奇怪的是,如果我创建一个msg并设置多个枚举,然后在C#中再次读取它,它确实有效…:-(

协议缓冲区和枚举组合

在Protobufs中,枚举类型的字段只允许具有在枚举中指定的精确数值之一。也就是说,不能使用枚举类型的字段作为位字段。如果您想要一个位字段,则需要使用像int32这样的整数类型。这条规则实际上甚至适用于具有数字枚举类型的语言,如C++——如果从连线读取的枚举类型的protobuf字段具有无效值,则它将被视为未知字段,从而被隐藏。

如果切换到整数,那么现在当然要解决如何声明标志值的问题。不幸的是,Protobufs没有提供定义常量的好方法。正如您在自我回答中所建议的,您可以使用伪枚举定义作为破解,但请注意,数值不一定在所有语言中都可用。它适用于C++和Python,因为它们使用数字枚举(显然C#也使用?)。在Java中,Protobuf枚举有一个.getNumber()方法,您可以使用它来获取数值;否则,普通的Java枚举不是数字的。

(此外:我是谷歌大部分开源Protobuf代码的作者。我也是Cap‘n Proto的作者,这是一个新的非谷歌项目,旨在取代Protobufs。除其他优势外,Cap‘n Proto支持在模式文件中定义常量。但是,截至本文撰写之时,C#支持还没有准备好(尽管正在进行中!)。)

如果您不需要挤出每一寸效率(提示:您可能不需要),那么只需使用枚举值数组。

message Msg {
    // ...
    enum Code
    {
        CODE_UNSPECIFIED = 0;
        CODE_MSG = 1;
        CODE_FILE = 2;
        CODE_APPROVE = 3;
        CODE_ACK = 4;
        CODE_ERROR_SENDING = 5;
        CODE_WORLD = 6;
    }
    repeated Code codes = 5;
}

官方protobuf文档建议您保留一个等于0的枚举条目,以表示类似"0"的意思;未知";。它真正针对的是用作非重复值的枚举(因为在proto3中,0枚举值和unset之间没有区别),但值得所有枚举遵循,以及用枚举名称前缀枚举值的约定,如上所述。

我找到了一个的解决方案

需要一个int持有者。

message Foo {
  enum Flags {
    FLAG1 = 0x01;
    FLAG2 = 0x02;
    FLAG3 = 0x04;
  }
  // Bitwise-OR of Flags.
  optional uint32 flags = 1;
  • 嗯,这是唯一的解决方案吗

您可以使用message而不是enums,并使用bool类型作为所需的标志。

下面是一个简单的闹钟模式的例子,可以在一周中设置多天:

message Alarm {
    uint32 hour = 1;
    uint32 minute = 2;
    bool repeat = 3;
    DaysOfWeek daysOfWeek = 4;
    message DaysOfWeek {
        bool sunday = 1;
        bool monday = 2;
        bool tuesday = 3;
        bool wednesday = 4;
        bool thursday = 5;
        bool friday = 6;
        bool saturday = 7;
    }
}

将字段定义为整数:

required int32 MsgCode = 1;

按照您的问题定义枚举,即使.proto文件中没有任何内容会引用它。

在代码中使用枚举字段。在C#中,这与您的示例类似(尽管这取决于您使用的库,例如protobuf-net非常出色,并且具有轻量级Enum.Field语法)。在Java中,使用带有_VALUE后缀的字段,例如MsgCodes.APPROVE_VALUE