如何使用protobuf的反射机制遍历所有已设置的FieldDescriptor*

背景

在项目开发中,由于需要使用到一个protobuf的API, 用于对不同Message的比较过程中,设置浮点数比较精度的API, MessageDifferencer::SetFractionAndMargin(const FieldDescriptor * field, double fraction, double margin),需要传入一个Message的FieldDescriptor,而项目中想对所有的浮点型的Field都设置默认精度,那么,就有了遍历一个Message中的所有FieldDescriptor的需求出来了。

实现方案

直接想在网上找代码片断,可惜了,百度和谷歌都没有谁有现成的代码出来,那就只能自己阅读API文档,做第一个贡献者吧。

自己调试了几个版本,终于算是把已知的一些问题都修复了,不排除还有一些未知的BUG,请大家指正。

主要使用的几个API,以及需要注意的问题。

1、如何获取当前Message的所有FieldDescriptor。

A)对于一个Message获取其下层的所有Field,可以通过Descriptor*获取,这个获取的是协议定义中的所有(无论是否被设置)

B)通过Relection中的ListFields去获取,这个是获取所有已设置的。(应该使用这个API)

2、对于Repeated的Field。通过Reflection的FieldSize去获取其Field的个数。

A)对于其类型是CPPTYPE_MESSAGE,需要进行递归遍历。

B)对于非CPPTYPE_MESSAGE,则直接返回,没有子层级的Field了。

这里直接上最终的实现代码,有类似需求的可以参考一下

遍历FieldDescriptor
/* 
  * 获取一个message的所有层级的FieldDescriptor
  */
static bool TraversalFieldDescript( const Message& message, std::vector< const FieldDescriptor*>& v_field_dpt) {
     const Descriptor* descriptor = message.GetDescriptor();
     const Reflection* reflection = message.GetReflection();
     if (NULL == descriptor) {
         LOG_ERR( "descriptor is null" );
         return false ;
     }  
     v_field_dpt.clear();
     DoTraversalFieldDescript(message, descriptor, v_field_dpt);
     return true ;
}  
static void DoTraversalFieldDescript( const Message& message,
                                 const Descriptor* descriptor,
                                 std::vector< const FieldDescriptor*>& v_field_dpt) {
     const Reflection* reflection = message.GetReflection();
     if (NULL == reflection) {
         LOG_ERR( "reflection is null" );
         return ;
     }  
     if (NULL == descriptor) {
         return ;
     }  
     const FieldDescriptor* field = NULL;
     vector< const FieldDescriptor*> v_field_list;
     reflection->ListFields(message, &v_field_list);
     for ( size_t i = 0; i < v_field_list.size(); ++i) {
         field = v_field_list[i];
         if (NULL == field) {
             LOG_ERR( "field is null" );
             return ;
         }
 
         LOG_DBG( "field_name [%s] set" , field->full_name().c_str());
         //非复合类型,加到数组中返回
         if (FieldDescriptor::CPPTYPE_MESSAGE != field->cpp_type() &&
             !field->is_repeated()) {
             v_field_dpt.push_back(field);
             continue ;
         }
         // CPPTYPE_MESSAGE
         if (!field->is_repeated()) {
             //not repeated
             const Message& current_msg = reflection->GetMessage(message, field);
             v_field_dpt.push_back(field);
             const Descriptor* sub_dst = field->message_type();
             DoTraversalFieldDescript(current_msg, sub_dst, v_field_dpt);
         }
         else {
             int count = reflection->FieldSize(message, field);
             v_field_dpt.push_back(field);
             if (FieldDescriptor::CPPTYPE_MESSAGE != field->cpp_type()) {
                 continue ;
             }
             //repeated and CPPTYPE_MESSAGE
             for ( int j = 0; j < count; ++j) {
                 const Message& current_msg = reflection->GetRepeatedMessage(message, field, j);
                 const Descriptor* sub_dst = field->message_type();
                 DoTraversalFieldDescript(current_msg, sub_dst, v_field_dpt);
             }
         }
     }
}

 


猜你喜欢

转载自blog.csdn.net/dreamvyps/article/details/80968254