协议缓冲区和枚举组合?

时间:2014-11-07 21:12:53

标签: java c# 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;
        }
}

在我的C#中我试图:

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

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

删除组合 - 解决它

但我需要指定组合

问题

我该如何解决?

nb:

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

5 个答案:

答案 0 :(得分:6)

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

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

(旁白:我是谷歌大部分开源Protobuf代码的作者。我还是Cap'n Proto的作者,这是一个旨在取代的新的非谷歌项目Protobufs。除了其他优点之外,Cap' n Proto支持在模式文件中定义常量。但是,在撰写本文时,C#支持还没有准备好(虽然正在处理!)。

答案 1 :(得分:4)

您可以使用消息而不是枚举,并使用bool类型作为您需要的标记。

以下是一个简单闹钟架构的示例,其中可以设置一周中的多天:

aar

答案 2 :(得分:1)

我找到了解决方案(某种程度)

需要一个int持有人。

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

  // Bitwise-OR of Flags.
  optional uint32 flags = 1;
  • 嗯,这是唯一的解决方案吗?

答案 3 :(得分:1)

将字段定义为整数:

required int32 MsgCode = 1;

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

使用代码中的枚举字段。在C#中,它就像你的例子(虽然它取决于你使用的库(例如protobuf-net非常好并且具有轻量级的Enum.Field语法)。在Java中,使用带有{{1的字段}后缀,例如_VALUE

答案 4 :(得分:1)

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

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