11

这是我的原型文件:

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

删除组合 -确实解决了

但我需要指定组合

问题

我该如何解决?

注意:

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

4

5 回答 5

13

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

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

(旁白:我是 Google 大部分开源 Protobuf 代码的作者。我也是Cap'n Proto的作者,这是一个旨在替换 Protobufs 的较新的非 Google 项目。Cap'n Proto 支持定义模式文件中的常量。但是,在撰写本文时,C# 支持还没有准备好(尽管正在开发中!)。)

于 2014-11-08T22:25:45.587 回答
7

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

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

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

于 2017-03-09T09:55:52.817 回答
6

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

需要一个 int 持有人。

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

  // Bitwise-OR of Flags.
  optional uint32 flags = 1;
  • 嗯,这是唯一的解决方案吗?
于 2014-11-07T21:57:42.407 回答
6

您可以使用消息而不是枚举,并为您需要的标志使用 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;
    }
}
于 2017-02-05T16:34:11.223 回答
1

将字段定义为整数:

required int32 MsgCode = 1;

在您的问题中定义枚举,即使 .proto 文件中的任何内容都不会引用它。

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

于 2015-08-18T20:52:42.417 回答