协议缓冲区和枚举组合?

Roy*_*mir 7 c# java enums protocol-buffers protobuf-csharp-port

这是我的原型文件:

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;
        }
}
Run Code Online (Sandbox Code Playgroud)

在我的C#中我试图:

 msg = msg.ToBuilder().SetMsgCode(msg.MsgCode | MSG.Types.MsgCodes.ACK | MSG.Types.MsgCodes.APPROVE).Build();
 SendToJava(msg);
Run Code Online (Sandbox Code Playgroud)

但JAVA告诉我:缺少MsgCode(这是一个required)

删除组合 - 确实解决了它

但我需要指定组合

我该如何解决?

nb:

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

Art*_*cca 7

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

message Msg {
    // ...
    enum Code
    {
        MSG = 0;
        FILE = 1;
        APPROVE = 2;
        ACK = 3;
        ERROR_SENDING = 4;
        WORLD = 5;
    }
    repeated Code codes = 5;
}
Run Code Online (Sandbox Code Playgroud)

很久以后的编辑:官方 protobuf 文档建议您保留一个等于 0 的枚举条目,以表示“未知”之类的内容。它确实针对用作非重复值的枚举(因为在 proto3 中 0 枚举值和未设置之间没有区别),但对于所有枚举都值得遵循。在这种情况下,这意味着你要更换以上UNKNOWN = 0MSG = 1等等。


Roy*_*mir 6

我找到了一个解决方案(有点)

需要一个 int 持有人。

message Foo {
  enum Flags {
    FLAG1 = 0x01;
    FLAG2 = 0x02;
    FLAG3 = 0x04;
  }

  // Bitwise-OR of Flags.
  optional uint32 flags = 1;
Run Code Online (Sandbox Code Playgroud)
  • 嗯,这是唯一的解决方案吗?


Ken*_*rda 6

在Protobufs中,只允许枚举类型的字段具有枚举中指定的确切数值之一。也就是说,您不能将枚举类型的字段用作位字段。如果要使用位域,则需要使用整数类型,例如int32。该规则实际上甚至适用于具有数字枚举类型的语言,例如C ++ -如果从电线读取的枚举类型的protobuf字段具有无效值,它将被视为未知字段并因此被隐藏。

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

(此外:我是Google大部分Protobuf开源代码的作者。我还是Cap'n Proto的作者,Cap'n Proto是一个旨在取代Protobufs的新型非Google项目。除其他优势外,Cap'n Proto还支持定义模式文件中的常量。但是,截至本文撰写时,C#支持尚未准备就绪(尽管正在开发中!)。


Lou*_*CAD 5

您可以使用message代替枚举,并为需要的标志使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 然而,这是相当低效的,因为每个字段都会有一个标签 ID (2认同)