Буферы протокола и перечисления комбинаций?
Это мой прото-файл:
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
и установить несколько перечислений, а затем снова читает его в C# - это работает...:-(
5 ответов
В Protobufs поле типа enum может иметь только одно из точных числовых значений, указанных в перечислении. То есть вы не можете использовать поле с типом enum в качестве битового поля. Если вы хотите битовое поле, вам нужно использовать целочисленный тип, такой как int32
, На самом деле это правило применяется даже в тех языках, которые имеют числовые типы перечисления, например C++ - если поле протобуфа с типом перечисления, считываемое из провода, имеет недопустимое значение, оно будет обрабатываться как неизвестное поле и, следовательно, будет скрыто.
Если вы переключаетесь на целые числа, у вас, конечно, теперь есть проблема, как объявлять значения флагов. К сожалению, Protobufs не предоставляет хорошего способа определения констант. Как вы предложили в своем ответе, вы можете использовать фиктивное определение перечисления в качестве хака, но учтите, что числовое значение не обязательно будет доступно на всех языках. Он работает в C++ и Python, так как они используют числовые перечисления (и, очевидно, C# тоже?). В Java перечисления Protobuf имеют .getNumber()
метод, который вы можете использовать, чтобы получить числовое значение; в противном случае обычные перечисления Java не являются числовыми.
(Кроме того: я являюсь автором большей части кода Protobuf с открытым исходным кодом Google. Я также являюсь автором Cap'n Proto, нового не-Google проекта, направленного на замену Protobuf. Среди других преимуществ Cap'n Proto поддерживает определение константы в файлах схемы. Но на момент написания этой статьи поддержка C# еще не была готова (хотя работа над ней ведется!).)
Если вам не нужно выжимать каждый последний дюйм эффективности (подсказка: вы, вероятно, этого не делаете), тогда просто используйте массив значений enum.
message Msg {
// ...
enum Code
{
MSG = 0;
FILE = 1;
APPROVE = 2;
ACK = 3;
ERROR_SENDING = 4;
WORLD = 5;
}
repeated Code codes = 5;
}
Я нашел решение (вроде)
нужен владелец int.
message Foo {
enum Flags {
FLAG1 = 0x01;
FLAG2 = 0x02;
FLAG3 = 0x04;
}
// Bitwise-OR of Flags.
optional uint32 flags = 1;
- Ммм, это единственное решение?
Вы можете использовать message вместо enums и использовать bool type для нужных вам флагов.
Вот пример простой схемы будильника, где ее можно установить на несколько дней недели:
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 не будет ссылаться на него.
Используйте поля enum в вашем коде. В C# это похоже на ваш пример (хотя это зависит от того, какую библиотеку вы используете (например, protobuf-net превосходен и имеет легкий синтаксис Enum.Field). В Java используйте поля с _VALUE
суффикс, например MsgCodes.APPROVE_VALUE
,