1. 程式人生 > >protobuf通過反射來賦值

protobuf通過反射來賦值

最近因為專案邏輯方面都做的差不多了,於是趕緊去做做測試工作,免得專案上線之後出問題,於是打算用配置的形式做一個類似與白盒測試工具的東西出來。

因為專案使用pb來做協議通訊,所以配置的xml也是類似於pb,將pb的欄位和型別配置進去,然後加上值,一個協議結構就可以了,現在只能通過修改值來做測試,後面會改動的更智慧化一些,例如某個行為的次數,某個行為更隨機等等。

去讀了一下陳碩的關於pb處理協議的反射,學到了不少東西,同時對pb的一些東西理解更深刻了,google還是大牛很多。

1.如何處理pb的反射,通過協議字串動態生成一個協議

pb提供了一個強大的DescriptorPool::generated_pool()

程式碼如下:

    inline google::protobuf::Message* CreateMessage(const std::string& msg)
    {
        google::protobuf::Message* message = NULL;
        const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + msg);
        if (descriptor)
        {
            const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
            if (prototype)
            {
                message = prototype->New();
            }
        }

        return message;
    }

    inline void ReleaseMessage(google::protobuf::Message* pMsg)
    {
        if (NULL != pMsg)
        {
            pMsg->Clear();
            delete pMsg;
        }
    }

這兩個函式可以動態生成pb的message,其中ProtoMsg是你pb package的名字

2.通過反射將配置中的值設定進pb欄位

pb的Message基類提供了一個Reflection,這個類非常強大

程式碼如下

    // mstrCurMsg 當前正在執行的協議
    google::protobuf::Message* pMsg = Test::CreateMessage(mstrCurMsg);
    const google::protobuf::Descriptor* pDescriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("ProtoMsg." + mstrCurMsg);
    assert(NULL != pDescriptor);
	
	// 這一個可以獲取到反射類,然後可以將配置中值賦值進去
    const google::protobuf::Reflection* pReflection = pMsg->GetReflection();
    assert(NULL != pReflection);

    for (int i = 0; i < pDescriptor->field_count(); ++i)
    {
        const google::protobuf::FieldDescriptor* pFieldDescriptor = pDescriptor->field(i);
        assert(NULL != pFieldDescriptor);

        const std::string& strFieldName = pFieldDescriptor->name();
        
        const TestConfigModule::MsgEntry* pMsgEntry = pMsgStruct->GetMsgEntry(strFieldName);
        assert(NULL != pMsgEntry);

        // 讀取欄位型別,順帶可以做型別檢查
        assert(pMsgEntry->mnType == pFieldDescriptor->type());

        // 設定值
        switch (pMsgEntry->mnType)
        {
        case Test::TYPE_STRING:
            pReflection->SetString(pMsg, pFieldDescriptor, pMsgEntry->mstrValue);
            break;
		// ...
        default:
            break;
        }
    }

    std::string strData;
    if (!pMsg->SerializeToString(&strData))
    {
        m_pLogModule->LogNormal("Test stop, cannot SerializeToString ", mstrCurMsg, __FUNCTION__, __LINE__);
        return;
    }

    Test::ReleaseMessage(pMsg);

通過這樣的步驟,就可以自動建立message和對field賦值了,如果你也有pb的使用經驗和技巧,歡迎分享