Protocol Buffers 反射及相关 API

http://name5566.com/2473.html


利用 Protocol Buffers 的反射(Reflection)和相关机制能够实现一些灵活的功能。

通过 message 名称构建 message 对象

Protocol buffers 提供了一套通过名字来创建 message 对象的方法:

  1. 获取 MessageFactory 对象
    MessageFactory 类提供了一个 generated_factory() 的静态函数,此静态函数可以获取一个 MessageFactory 对象,此 MessageFactory 对象能够用来创建被编译入程序的所有的 message 对象。注意,此 Factory 是一个 Singleton,因此重复多次调用 generated_factory 函数不会创建多个 MessageFactory 对象,另外调用者也不能通过调用 delete 删除此对象。
  2. 获取 DescriptorPool 对象
    通过 DescriptorPool 类的 generated_pool() 静态函数能够获取 DescriptorPool 的指针。此 DescriptorPool 中包含了被编译入程序的 message 的 descriptor。generated_pool 类似于 generated_factory 函数,可以被重复调用多次而不会创建多个 DescriptorPool 对象。
  3. 获取 message descriptor
    有了 DescriptorPool 对象就可以获取到 message 的 descriptor 了。常见的一个函数是 const Descriptor * FindMessageTypeByName(const string & name) const,此函数可以通过 message 名字获取到顶层 message 的 descriptor。当然除此之外还有一些 API 可以用来获取 message discriptor,可以参考相关文档,这里就不一一详述了。
  4. 获取 message prototype 并构建 message 对象
    前面已经讲述了获取 MessageFactory 对象的方法,有了 MessageFactory 对象就可以通过函数 MessageFactory::GetPrototype(const Descriptor * type) 获取 message prototype(实质上就是一个 message 对象)。通过调用 message prototype 的 New 函数则可以构造此类型的 message。
    对同一个 Descriptor 多次调用 MessageFactory::GetPrototype 函数将返回同一个对象。通过调用 prototype 的 New 函数构造的 message 对象必须在 MessageFactory 销毁前销毁。

具体编码如下:

 
 
  1. #include <google/protobuf/message.h>
  2. #include <google/protobuf/descriptor.h>
  3.  
  4. // 这样使用:
  5. // createMessageByName("tutorial.AddressBook");
  6. // 这里的 tutorial 为 package 名,AddressBook 为 message 名
  7. google::protobuf::Message* createMessageByName(const std::string& name)
  8. {
  9. const google::protobuf::Descriptor* descriptor
  10. = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(name);
  11. if (!descriptor)
  12. return NULL;
  13. const google::protobuf::Message* prototype
  14. = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
  15. if (!prototype)
  16. return NULL;
  17. return prototype->New();
  18. }
遍历被编译的 message

遍历某个 .proto 文件中的所有的顶层 message 可以通过直接解析 .proto 文件来完成(利用 google::protobuf::compiler 相关接口)。如果这个 .proto 文件被编译的 C++ 文件被编译进了程序,那么则无需解析 .proto 文件:

 
 
  1. #include <google/protobuf/message.h>
  2. #include <google/protobuf/descriptor.h>
  3.  
  4. void IterateProtoFile(const std::string& name)
  5. {
  6. // 在 DescriptorPool 中通过 .proto 文件名获取到 FileDescriptor
  7. // FileDescriptor 对象描述了整个 .proto 文件
  8. const google::protobuf::FileDescriptor* fileDescriptor
  9. = google::protobuf::DescriptorPool::generated_pool()->FindFileByName(name);
  10. if (!fileDescriptor)
  11. return;
  12.  
  13. // 遍历整个 .proto 文件中定义的顶层 message
  14. for (int i=0; i<fileDescriptor->message_type_count(); ++i)
  15. {
  16. // message_type 函数参数取值范围在 0 <= index < message_type_count()
  17. // 索引值 i 对应 message 在 .proto 文件中的定义的顺序
  18. const google::protobuf::Descriptor* descriptor = fileDescriptor->message_type(i);
  19.  
  20. // ...
  21. }
  22. }

一个值得注意的问题是,(我所用到的)反射的 API 需要在 main 函数执行之后调用,例如:

 
 
  1. class Test()
  2. {
  3. public:
  4. Test() {
  5. const google::protobuf::FileDescriptor* fileDescriptor
  6. = google::protobuf::DescriptorPool::generated_pool()->FindFileByName("name");
  7. }
  8. };
  9.  
  10. Test g_test;

此例中 fileDescriptor 可能为 NULL。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值