2016-04-18 2 views
2

Я использую grpc в приложении C++. На стороне клиента мне нужно рефлексивно запрашивать логическое значение из сообщения с использованием отражения.с использованием protobuf reflection для получения логического дескриптора поля в C++

Ответное сообщение показано ниже. К сожалению, я не могу видеть дескрипторы полей для bool mAP-поля - однако я могу видеть FieldDescriptors для строковых полей. Что я делаю неправильно?

Джон

message Response { 
    // OTP Connection Status 
    enum OTPConnStatus { 
     Disconnected    = 0; 
     Connected     = 1; 
     InvalidCS     = 2; 
     DiscRequest    = 3; 
    } 

    // define the fields 
    RXMessageType mMessageType = 1; 
    bool mAP      = 2; 
    OTPConnStatus mCS1   = 3; 
    OTPConnStatus mCS2   = 4; 
    OTPConnStatus mCS3   = 5; 
    OTPConnStatus mCS4   = 6; 
    string mOTP1     = 7; 
    string mOTP2     = 8; 
    string mOTP3     = 9; 
    string mOTP4     = 10; 
} 
const auto reflection = pMessage->GetReflection(); 
std::vector<const FieldDescriptor*> fields; 
pMessage->GetReflection()->ListFields(*pMessage, &fields); 
const auto fieldIter = std::find_if(fields.cbegin(), fields.cend(), 
    [&lcFieldName](const FieldDescriptor* next) { 
     return boost::iequals(next->name(), lcFieldName); 
    }); 
if (fieldIter != fields.cend()) { 
    std::string result; 
    auto fieldDescriptor = *fieldIter; 
    if (!fieldDescriptor->is_repeated()) { 
     switch (fieldDescriptor->cpp_type()) { 
     case FieldDescriptor::CPPTYPE_INT32: 
      result = std::to_string(reflection->GetInt32 (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_INT64: 
      result = std::to_string(reflection->GetInt64 (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_UINT32: 
      result = std::to_string(reflection->GetUInt32 (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_UINT64: 
      result = std::to_string(reflection->GetUInt64 (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_DOUBLE: 
      result = std::to_string(reflection->GetDouble (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_FLOAT: 
      result = std::to_string(reflection->GetFloat (
       *pMessage, fieldDescriptor)); 
      break; 
     case FieldDescriptor::CPPTYPE_BOOL: 
      result = reflection->GetBool(
       *pMessage, fieldDescriptor) ? 
       "true" : "false"; 
      break; 
     case FieldDescriptor::CPPTYPE_ENUM: 
      result = reflection->GetEnum(
       *pMessage, fieldDescriptor)-> 
        full_name(); 
      break; 
     case FieldDescriptor::CPPTYPE_STRING: 
      result = reflection->GetString(
       *pMessage, fieldDescriptor); 
      break; 
     case FieldDescriptor::CPPTYPE_MESSAGE: 
      //result = reflection->GetMessage(
      // *pMessage, fieldDescriptor); 
      break; 
     } 
    } 
    std::cout << result << std::endl; 
    exit(0); 
} else { 

EDIT: Я нашел применение в Protobuf используется для печати сообщений, которые я использовал для печати содержимого. Вот результаты:

const auto reflection = pMessage->GetReflection(); 
std::string formatted; 
pb::TextFormat::PrintToString(*pMessage, &formatted); 
std::cout << formatted; 

Печатные:

mMessageType: OneTimePassword 
mOTP1: "TAILNO1" 
mOTP2: "TAILNO2" 
mOTP3: "TAILNO3" 
mOTP4: "TAILNO4" 

Кроме того, обратите внимание, что булево поле в вопросе «карта» создается сервером. Глядя на сгенерированный код CAService.pb.h и сравнивая MessageType (у которого есть дескриптор рабочего поля) на поле mAP, которого нет, может быть полезно пользователям protobuf, чтобы показать мне ошибку в моем подходе.

// optional .ca.RXMessageType mMessageType = 1; 
inline void OTPResponse::clear_mmessagetype() { 
    mmessagetype_ = 0; 
} 
inline ::ca::RXMessageType OTPResponse::mmessagetype() const { 
    // @@protoc_insertion_point(field_get:ca.OTPResponse.mMessageType) 
    return static_cast<::ca::RXMessageType>(mmessagetype_); 
} 
inline void OTPResponse::set_mmessagetype(::ca::RXMessageType value) { 

    mmessagetype_ = value; 
    // @@protoc_insertion_point(field_set:ca.OTPResponse.mMessageType) 
} 

// optional bool mAP = 2; 
inline void OTPResponse::clear_map() { 
    map_ = false; 
} 
inline bool OTPResponse::map() const { 
    // @@protoc_insertion_point(field_get:ca.OTPResponse.mAP) 
    return map_; 
} 
inline void OTPResponse::set_map(bool value) { 

    map_ = value; 
    // @@protoc_insertion_point(field_set:ca.OTPResponse.mAP) 
} 
+0

Показывает ли это, когда вы печатаете все имена полей? Может ли это переименовать по какой-то странной причине? Почему вы используете нечувствительность к регистру в фильтре имени? –

+0

@StefanHaustein Результат ListFields дает мне 5 дескрипторов полей - один для mMessageType и остальные 4 строковых поля mOTP1-4. члены по умолчанию в нижнем регистре, поэтому я использую нечувствительное к регистру сравнение. Также lcFieldName передается пользователем на клавиатуре. – johnco3

+1

Reflection :: ListFields перечисляет только те поля, которые установлены, может ли это объяснить отсутствие логических и перечислимых полей? –

ответ

3

Reflection::ListFields() содержит только те поля, которые в настоящее время установлены. Чтобы перебрать все поля или найти определенное поле, используйте методы доступа к полю в Descriptor. Вы можете получить дескриптор сообщения из сообщения (или из объекта Reflection), используя GetDescriptor.

+0

Приятно поблагодарить вас за соблюдение всех комментариев! – johnco3