简体   繁体   English

协议缓冲区和枚举组合?

[英]Protocol buffers and enums combinations?

This is my proto file :这是我的原型文件:

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;
        }
}

In my C# I'm trying to :在我的 C# 中,我试图:

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

But the JAVA tells me : missing MsgCode ( which is a required )但是 JAVA 告诉我:缺少 MsgCode(这是required

Removing the combination - does solve it删除组合 -确实解决了它

But I need to specify combinations但我需要指定组合

Question

How can I solve it ?我该如何解决?

nb :注意:

The weird thing is that if I create a msg and set multiple enums , and then reads it in C# again - it does work...:-(奇怪的是,如果我创建一个msg并设置多个 enums ,然后再次在 C# 中读取它 - 它确实有效...:-(

In Protobufs, an enum-typed field is only allowed to have one of the exact numeric values specified in the enum.在 Protobufs 中,枚举类型的字段只允许具有枚举中指定的精确数值之一。 That is to say, you cannot use an enum-typed field as a bitfield.也就是说,您不能将枚举类型的字段用作位字段。 If you want a bitfield, you need to use an integer type like int32 .如果你想要一个位域,你需要使用像int32这样的整数类型。 This rule actually applies even in languages that have numeric enum types, like C++ -- if an enum-typed protobuf field read from the wire has an invalid value, it will be treated like an unknown field and thus hidden.这个规则实际上甚至适用于具有数字枚举类型的语言,如 C++——如果从线路读取的枚举类型的 protobuf 字段具有无效值,它将被视为未知字段并因此隐藏。

If you switch to integers, you of course now have the problem of how to declare flag values.如果您切换到整数,您当然会遇到如何声明标志值的问题。 Unfortunately Protobufs provides no good way to define constants.不幸的是,Protobufs 没有提供定义常量的好方法。 As you suggested in your self-answer, you can use a dummy enum definition as a hack, but note that the numeric value won't necessarily be available in all languages.正如您在自我回答中所建议的那样,您可以使用虚拟枚举定义作为一种技巧,但请注意,该数值不一定适用于所有语言。 It works in C++ and Python since they use numeric enums (and apparently C# too?).它适用于 C++ 和 Python,因为它们使用数字枚举(显然也是 C#?)。 In Java, Protobuf enums have a .getNumber() method which you can use to get the numeric value;在 Java 中,Protobuf 枚举有一个.getNumber()方法,您可以使用它来获取数值; otherwise, normal Java enums are not numeric.否则,普通的 Java 枚举不是数字。

(Aside: I'm the author of most of Google's open source Protobuf code. I'm also the author of Cap'n Proto , a newer non-Google project aimed at replacing Protobufs. Among other advantages, Cap'n Proto supports defining constants in schema files. But, as of this writing C# support is not ready yet (though being worked on!).) (另外:我是 Google 大部分开源 Protobuf 代码的作者。我也是Cap'n Proto的作者,这是一个旨在取代 Protobufs 的较新的非 Google 项目。除其他优点外,Cap'n Proto 支持定义模式文件中的常量。但是,在撰写本文时,C# 支持还没有准备好(尽管正在开发中!)。

If you don't need to squeeze out every last inch of efficiency (hint: you probably don't), then just use an array of enum values.如果您不需要挤出最后一英寸的效率(提示:您可能不需要),那么只需使用枚举值数组。

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

Much later edit: The official protobuf docs recommend you reserve an enum entry equal to 0 to mean something like "unknown".很久以后的编辑:官方 protobuf 文档建议您保留一个等于 0 的枚举条目,以表示“未知”之类的内容。 It's really targetted at enums that are used as non-repeated values (because in proto3 there's no difference between the 0 enum value and unset) but worth following for all enums.它真正针对用作非重复值的枚举(因为在 proto3 中 0 枚举值和未设置之间没有区别),但对于所有枚举都值得遵循。 In this case, that means you'd replace the above with UNKNOWN = 0 , MSG = 1 , etc.在这种情况下,这意味着您可以将上述内容替换为UNKNOWN = 0MSG = 1等。

I found a solution (sort of)我找到了一个解决方案(有点)

need an int holder.需要一个 int 持有人。

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

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

You can use message instead of enums, and use bool type for the flags you need.您可以使用消息而不是枚举,并使用 bool 类型作为您需要的标志。

Here's an example for a simple Alarm Clock schema where it can be set for multiple days in the week:下面是一个简单的闹钟模式的例子,它可以在一周中设置多天:

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;
    }
}

Define the field as an integer:将字段定义为整数:

required int32 MsgCode = 1;

Define the enum as in your question, even though nothing in the .proto file will reference it.将枚举定义为您的问题,即使 .proto 文件中没有任何内容会引用它。

Use the enum fields in your code.在代码中使用枚举字段。 In C#, it's like your example (although it depends on which library you use, eg protobuf-net is excellent and has a lightweight Enum.Field syntax).在 C# 中,它就像您的示例(尽管它取决于您使用的库,例如protobuf-net非常出色并且具有轻量级的 Enum.Field 语法)。 In Java, use the fields with the _VALUE suffix, eg MsgCodes.APPROVE_VALUE .在Java中,使用与该领域_VALUE后缀,如MsgCodes.APPROVE_VALUE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM