[英]Protocol buffers and enums combinations?
这是我的原型文件:
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# 中读取它 - 它确实有效...:-(
在 Protobufs 中,枚举类型的字段只允许具有枚举中指定的精确数值之一。 也就是说,您不能将枚举类型的字段用作位字段。 如果你想要一个位域,你需要使用像int32
这样的整数类型。 这个规则实际上甚至适用于具有数字枚举类型的语言,如 C++——如果从线路读取的枚举类型的 protobuf 字段具有无效值,它将被视为未知字段并因此隐藏。
如果您切换到整数,您当然会遇到如何声明标志值的问题。 不幸的是,Protobufs 没有提供定义常量的好方法。 正如您在自我回答中所建议的那样,您可以使用虚拟枚举定义作为一种技巧,但请注意,该数值不一定适用于所有语言。 它适用于 C++ 和 Python,因为它们使用数字枚举(显然也是 C#?)。 在 Java 中,Protobuf 枚举有一个.getNumber()
方法,您可以使用它来获取数值; 否则,普通的 Java 枚举不是数字。
(另外:我是 Google 大部分开源 Protobuf 代码的作者。我也是Cap'n Proto的作者,这是一个旨在取代 Protobufs 的较新的非 Google 项目。除其他优点外,Cap'n Proto 支持定义模式文件中的常量。但是,在撰写本文时,C# 支持还没有准备好(尽管正在开发中!)。
如果您不需要挤出最后一英寸的效率(提示:您可能不需要),那么只需使用枚举值数组。
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
等。
我找到了一个解决方案(有点)
需要一个 int 持有人。
message Foo {
enum Flags {
FLAG1 = 0x01;
FLAG2 = 0x02;
FLAG3 = 0x04;
}
// Bitwise-OR of Flags.
optional uint32 flags = 1;
您可以使用消息而不是枚举,并使用 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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.