Буферы протокола и перечисления комбинаций?

Это мой прото-файл:

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,

Другие вопросы по тегам