您的位置:首页 > Web前端

Protocol Buffers 反射及相关 API

2013-11-28 13:33 513 查看
http://name5566.com/2473.html

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


通过 message 名称构建 message 对象

Protocol buffers 提供了一套通过名字来创建 message 对象的方法:
获取 MessageFactory 对象
MessageFactory 类提供了一个 generated_factory() 的静态函数,此静态函数可以获取一个 MessageFactory
对象,此 MessageFactory 对象能够用来创建被编译入程序的所有的 message 对象。注意,此 Factory 是一个 Singleton,因此重复多次调用 generated_factory 函数不会创建多个 MessageFactory 对象,另外调用者也不能通过调用 delete 删除此对象。
获取 DescriptorPool 对象

通过 DescriptorPool 类的 generated_pool() 静态函数能够获取 DescriptorPool 的指针。此
DescriptorPool 中包含了被编译入程序的 message 的 descriptor。generated_pool 类似于 generated_factory 函数,可以被重复调用多次而不会创建多个 DescriptorPool 对象。
获取 message descriptor

有了 DescriptorPool 对象就可以获取到 message 的 descriptor 了。常见的一个函数是 const Descriptor * FindMessageTypeByName(const string & name) const,此函数可以通过 message 名字获取到顶层 message 的 descriptor。当然除此之外还有一些 API 可以用来获取 message discriptor,可以参考相关文档,这里就不一一详述了。
获取 message prototype 并构建 message 对象

前面已经讲述了获取 MessageFactory 对象的方法,有了 MessageFactory 对象就可以通过函数 MessageFactory::GetPrototype(const Descriptor * type) 获取 message prototype(实质上就是一个 message 对象)。通过调用 message prototype 的 New 函数则可以构造此类型的 message。

对同一个 Descriptor 多次调用 MessageFactory::GetPrototype 函数将返回同一个对象。通过调用 prototype 的 New 函数构造的 message 对象必须在 MessageFactory 销毁前销毁。

具体编码如下:
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
 
// 这样使用:
// createMessageByName("tutorial.AddressBook");
// 这里的 tutorial 为 package 名,AddressBook 为 message 名
google::protobuf::Message* createMessageByName(const std::string& name)
{
const google::protobuf::Descriptor* descriptor
= google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(name);
if (!descriptor)
return NULL;
const google::protobuf::Message* prototype
= google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
if (!prototype)
return NULL;
return prototype->New();
}


遍历被编译的 message

遍历某个 .proto 文件中的所有的顶层 message 可以通过直接解析 .proto 文件来完成(利用 google::protobuf::compiler 相关接口)。如果这个 .proto 文件被编译的 C++ 文件被编译进了程序,那么则无需解析 .proto 文件:
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
 
void IterateProtoFile(const std::string& name)
{
// 在 DescriptorPool 中通过 .proto 文件名获取到 FileDescriptor
// FileDescriptor 对象描述了整个 .proto 文件
const google::protobuf::FileDescriptor* fileDescriptor
= google::protobuf::DescriptorPool::generated_pool()->FindFileByName(name);
if (!fileDescriptor)
return;
 
// 遍历整个 .proto 文件中定义的顶层 message
for (int i=0; i<fileDescriptor->message_type_count(); ++i)
{
// message_type 函数参数取值范围在 0 <= index < message_type_count()
// 索引值 i 对应 message 在 .proto 文件中的定义的顺序
const google::protobuf::Descriptor* descriptor = fileDescriptor->message_type(i);
 
// ...
}
}

一个值得注意的问题是,(我所用到的)反射的 API 需要在 main 函数执行之后调用,例如:
class Test()
{
public:
Test() {
const google::protobuf::FileDescriptor* fileDescriptor
= google::protobuf::DescriptorPool::generated_pool()->FindFileByName("name");
}
};
 
Test g_test;

此例中 fileDescriptor 可能为 NULL。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: