【问题标题】:using protobuf reflection to get a boolean field descriptor in c++使用 protobuf 反射在 C++ 中获取布尔字段描述符
【发布时间】:2016-04-18 01:07:57
【问题描述】:

我在 C++ 应用程序中使用 grpc。在客户端,我需要使用反射从消息中反射性地查询布尔值。

响应消息如下所示。不幸的是,我看不到 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 {

编辑:我在 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)
}

【问题讨论】:

  • 打印所有字段名称时是否显示?它会因为一些奇怪的原因而被重命名吗?为什么在名称过滤器中使用不区分大小写的等号?
  • @StefanHaustein ListFields 的结果为我提供了 5 个字段描述符 - 一个用于 mMessageType,其余 4 个字符串字段 mOTP1-4。成员默认为小写,这就是我使用不区分大小写比较的原因。 lcFieldName 也是由用户在键盘上传入的。
  • Reflection::ListFields 仅列出设置的字段,这可以解释布尔和枚举字段的省略吗?
  • @StefanHaustein 很好的建议,但不幸的是,事实并非如此,我编辑了问题以显示额外的打印输出并生成的代码将一个确实有描述符的字段与这个 mAP 字段没有进行对比。希望这会有用。谢谢
  • 我会尝试的事情: 1. 在通过 GetReflection 打印字段名称之前,将本地 bool 字段设置为非默认值。 2.使用消息描述符而不是GetReflection列出字段名称

标签: c++ reflection protocol-buffers descriptor


【解决方案1】:

Reflection::ListFields() 仅列出当前设置的字段。要迭代所有字段或搜索特定字段,请使用Descriptor 中的字段访问方法。您可以使用GetDescriptor从消息(或Reflection对象)中获取消息描述符。

【讨论】:

  • 非常感谢您跟进所有 cmets!
猜你喜欢
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多