利用反射读写message记录

一、前言

最近有个需求,需要在运行时去读写message。查阅资料之后,发现proto是支持反射的。可以利用反射完成这个需求。

二、Protobuf中的反射原理

反射原理的部分可以参考这篇文章:深入 ProtoBuf - 反射原理解析

反射使用的部分可以参考这篇文章:巧用 Protobuf 反射来优化代码,拒做 PB Boygoogle protobuf 反射机制学习笔记

三、各种类型的反射实践记录

3.1 反射元信息来源

反射是需要元信息的,protobuf里面正常的元信息来源是proto文件,转化为C++文件之后,则来源于C++文件。如果不生成C++文件的话,则元信息的来源需要动态编译这些proto文件获取。相关代码打算另外再写一篇关于proto动态编译相关文章的时候再贴上去。

3.2 反射读写各种类型记录

这些类型的读写操作都是靠Message对象中的反射类Reflection和字段描述类FieldDescriptor进行配合实现的。

int32的读写

读取:

int32 ResultInt32 = BaseReflection->GetInt32(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetInt32(MessageInstance, TargetFieldDescriptor, Int32Value);

int64的读写

读取:

int64 ResultInt64 = BaseReflection->GetInt64(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetInt64(MessageInstance, TargetFieldDescriptor, Int64Value);

uint32的读写

读取:

uint32 ResultUint32 = BaseReflection->GetUInt32(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetUInt32(MessageInstance, TargetFieldDescriptor, Uint32Value);

uint64的读写

读取:

uint64 ResultUint64 = BaseReflection->GetUInt64(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetUInt64(MessageInstance, TargetFieldDescriptor, Uint64Value);

double的读写

读取:

double ResultDouble = BaseReflection->GetDouble(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetDouble(MessageInstance, TargetFieldDescriptor, DoubleValue);

float的读写

读取:

float ResultFloat = BaseReflection->GetFloat(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetFloat(MessageInstance, TargetFieldDescriptor, FloatValue);

bool的读写

读取:

bool ResultBool = BaseReflection->GetBool(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetBool(MessageInstance, TargetFieldDescriptor, BoolValue);

enum的读写(特殊)

enum的读写稍微特殊一点,enum的值本身也有一个Descriptor(EnumValueDescriptor)对其进行描述,所以需要先将我们得到的enum值转化为EnumValueDescriptor,然后再进行写入。

读取:

const EnumValueDescriptor* TargetEnumValueDescriptor = BaseReflection->GetEnum(*TargetMessage, TargetFieldDescriptor);
UE_LOG(LogTemp, Warning, TEXT("TargetEnumValueDescriptor->number : %d"), TargetEnumValueDescriptor->number()); // TargetEnumValueDescriptor->number()是enum值的序号,可以用序号来代替原有的enum值

写入:

const EnumDescriptor* TargetEnumDescriptor = TargetFieldDescriptor->enum_type();
const EnumValueDescriptor* TargetEnumValueDescriptor = TargetEnumDescriptor->FindValueByNumber(ResultValue);
ReflectionInstance->SetEnum(MessageInstance, TargetFieldDescriptor, TargetEnumValueDescriptor);

string的读写

读取:

string ResultString = BaseReflection->GetString(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetString(MessageInstance, TargetFieldDescriptor, std::string(TCHAR_TO_UTF8(*StrValue)));

message的读写

读取:

const Message& SubMessage = BaseReflection->GetMessage(*TargetMessage, TargetFieldDescriptor);

写入:

ReflectionInstance->SetAllocatedMessage(MessageInstance, ResultSubMessage, TargetFieldDescriptor); // 子协议赋值给父协议对应字段

repeated修饰的各种类型读写

一般的repeated类型都使用的AddXXX()系列的接口就行,例如repeated int32;特殊一点的repeated类型,例如repeated enum和repeated message。

读取:

int32 RepeatedCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个repeated的个数
for (int32 j = 0; j < RepeatedCount; ++j)
{
    // 1.从message中获取这个字段对应的message repeated数据
    int32 SingleRepeatedInt32 = BaseReflection->GetRepeatedInt32(*TargetMessage, TargetFieldDescriptor, j); // 获得repeated中单个数据,即一个int32
}
int32 RepeatedCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个repeated的个数
TArray<uint8> TargetArray;
for (int32 j = 0; j < RepeatedCount; ++j)
{
    // 1.从message中获取这个字段对应的message repeated数据
    uint8 SingleEnumValue = BaseReflection->GetRepeatedEnumValue(*TargetMessage, TargetFieldDescriptor, j);
    TargetArray.Add(SingleEnumValue);
}
// 2.赋值
ArrayHelper.MoveAssign(&TargetArray);
int32 RepeatedCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个repeated的个数
TArray<UObject*> TargetArray;
for (int32 j = 0; j < RepeatedCount; ++j)
{
    // 1.从message中获取这个字段对应的message repeated数据
    const Message* SingleRepeatedMessageInstance = &BaseReflection->GetRepeatedMessage(*TargetMessage, TargetFieldDescriptor, j); // 获得repeated中单个数据,即一个message
    UObject* SingleRepeatedObject = GetUObjectFromMessage(SingleRepeatedMessageInstance); // 获得message对应的uobject数据
    TargetArray.Add(DuplicateObject(SingleRepeatedObject, nullptr)); // 需要用DuplicateObject进行深拷贝,不然TArray里面的元素全是指向最后一个元素。
}

写入:

 // repeated int32
for (int32 SingleObject : *TargetInt32s)
{
    // 设置数据
    ReflectionInstance->AddInt32(MessageInstance, TargetFieldDescriptor, SingleObject);
}
// repeated enum
for (uint8 SingleEnum : *TargetEnums)
{
    // 设置数据
    ReflectionInstance->AddEnumValue(MessageInstance, TargetFieldDescriptor, SingleEnum);
}
// repeated message
for (UObject* SingleObject : *TargetObjects)
{
    // 设置数据
    Message* ResultSubMessage = GetMessageFromObject(SingleObject);
    ReflectionInstance->AddAllocatedMessage(MessageInstance, TargetFieldDescriptor, ResultSubMessage); // 子协议赋值给父协议对应repeated字段
}

map修饰的各种类型的读写

map修饰符有一些特殊,从官网上的说明就可以发现,map的底层就是repeated message。所以读写操作和repeated修饰符有一些类似。

map介绍

读取:

// map key为int32,value为int32
int32 MapCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个map的个数
for (int32 j = 0; j < MapCount; ++j)
{
    // 1.从message中获取这个字段对应的message map数据
    const Message* SingleMapMessageInstance = &BaseReflection->GetRepeatedMessage(*TargetMessage, TargetFieldDescriptor, j); // 获得map中单个数据,即一个message	
    const FieldDescriptor* KeyFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("key"); // 获得单个数据中的key字段

    const FieldDescriptor* ValueFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("value"); // 获得单个数据中的value字段
    int32 KeyFieldValue = SingleMapMessageInstance->GetReflection()->GetInt32(*SingleMapMessageInstance, KeyFieldDescriptor); // 获得key字段的值
    int32 ValueFieldValue = SingleMapMessageInstance->GetReflection()->GetInt32(*SingleMapMessageInstance, ValueFieldDescriptor); // 获得value字段的值
}
// map key为int32,value为enum
int32 MapCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个map的个数
for (int32 j = 0; j < MapCount; ++j)
{
    // 1.从message中获取这个字段对应的message map数据
    const Message* SingleMapMessageInstance = &BaseReflection->GetRepeatedMessage(*TargetMessage, TargetFieldDescriptor, j); // 获得map中单个数据,即一个message	
    const FieldDescriptor* KeyFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("key"); // 获得单个数据中的key字段

    const FieldDescriptor* ValueFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("value"); // 获得单个数据中的value字段
    int32 KeyFieldValue = SingleMapMessageInstance->GetReflection()->GetInt32(*SingleMapMessageInstance, KeyFieldDescriptor); // 获得key字段的值
    uint8 ValueFieldValue = SingleMapMessageInstance->GetReflection()->GetEnumValue(*SingleMapMessageInstance, ValueFieldDescriptor); // 获得value字段的值
}
// map key为int32,value为message
int32 MapCount = BaseReflection->FieldSize(*TargetMessage, TargetFieldDescriptor); // 获得这个map的个数
TMap<int32, UObject*> TargetMap;
for (int32 j = 0; j < MapCount; ++j)
{
    // 1.从message中获取这个字段对应的message map数据
    const Message* SingleMapMessageInstance = &BaseReflection->GetRepeatedMessage(*TargetMessage, TargetFieldDescriptor, j); // 获得map中单个数据,即一个message	
    const FieldDescriptor* KeyFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("key"); // 获得单个数据中的key字段

    const FieldDescriptor* ValueFieldDescriptor = SingleMapMessageInstance->GetDescriptor()->FindFieldByName("value"); // 获得单个数据中的value字段
    int32 KeyFieldValue = SingleMapMessageInstance->GetReflection()->GetInt32(*SingleMapMessageInstance, KeyFieldDescriptor); // 获得key字段的值
    const Message& ValueFieldMessageInstance = SingleMapMessageInstance->GetReflection()->GetMessage(*SingleMapMessageInstance, ValueFieldDescriptor);

    UObject* ValueFieldObject = GetUObjectFromMessage(&ValueFieldMessageInstance); // 获得value字段的值								
    ULittleMessage* SpecObject = Cast<ULittleMessage>(ValueFieldObject);
    TargetMap.Add(KeyFieldValue, DuplicateObject(ValueFieldObject, nullptr)); // 需要用DuplicateObject进行深拷贝,不然TArray里面的元素全是指向最后一个元素。
}

写入:

// key为int32,value为int32
TMap<int32, int32>* TargetObjectMap = TargetMapProperty->ContainerPtrToValuePtr<TMap<int32, int32>>(SinglePropertyDataMap->ObjectBelongTo);
const Message* MapMessagePrototype = DynamicMessageFactoryInstance.GetPrototype(TargetFieldDescriptor->message_type());
for (TTuple<int32, int32> SingleObjectMap : *TargetObjectMap)
{
    Message* MapMessageInstance = MapMessagePrototype->New();
    const Reflection* MapReflection = MapMessageInstance->GetReflection();
    const FieldDescriptor* KeyFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("key");
    const FieldDescriptor* ValueFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("value");

    // 设置数据
    MapReflection->SetInt32(MapMessageInstance, KeyFieldDescriptor, SingleObjectMap.Key); // map单个元素中的key赋值
    MapReflection->SetInt32(MapMessageInstance, ValueFieldDescriptor, SingleObjectMap.Value); // map单个元素中的value赋值	 
    ReflectionInstance->AddAllocatedMessage(MessageInstance, TargetFieldDescriptor, MapMessageInstance); // 将单个元素赋值到map中
}
// key为int32,value为enum
TMap<int32, uint8>* TargetObjectMap = TargetMapProperty->ContainerPtrToValuePtr<TMap<int32, uint8>>(SinglePropertyDataMap->ObjectBelongTo);
const Message* MapMessagePrototype = DynamicMessageFactoryInstance.GetPrototype(TargetFieldDescriptor->message_type());
for (TTuple<int32, uint8> SingleObjectMap : *TargetObjectMap)
{
    Message* MapMessageInstance = MapMessagePrototype->New();
    const Reflection* MapReflection = MapMessageInstance->GetReflection();
    const FieldDescriptor* KeyFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("key");
    const FieldDescriptor* ValueFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("value");

    // 设置数据
    MapReflection->SetInt32(MapMessageInstance, KeyFieldDescriptor, SingleObjectMap.Key); // map单个元素中的key赋值
    MapReflection->SetEnumValue(MapMessageInstance, ValueFieldDescriptor, SingleObjectMap.Value); // map单个元素中的value赋值	 
    ReflectionInstance->AddAllocatedMessage(MessageInstance, TargetFieldDescriptor, MapMessageInstance); // 将单个元素赋值到map中
}
// key为int32,value为message的情况
TMap<int32, UObject*>* TargetObjectMap = TargetMapProperty->ContainerPtrToValuePtr<TMap<int32, UObject*>>(SinglePropertyDataMap->ObjectBelongTo);
const Message* MapMessagePrototype = DynamicMessageFactoryInstance.GetPrototype(TargetFieldDescriptor->message_type());
for (TTuple<int32, UObject*> SingleObjectMap : *TargetObjectMap)
{
    Message* MapMessageInstance = MapMessagePrototype->New();
    const Reflection* MapReflection = MapMessageInstance->GetReflection();
    const FieldDescriptor* KeyFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("key");
    const FieldDescriptor* ValueFieldDescriptor = MapMessageInstance->GetDescriptor()->FindFieldByName("value");

    // 设置数据
    MapReflection->SetInt32(MapMessageInstance, KeyFieldDescriptor, SingleObjectMap.Key); // map单个元素中的key赋值
    Message* ResultSubMessage = GetMessageFromObject(SingleObjectMap.Value);
    MapReflection->SetAllocatedMessage(MapMessageInstance, ResultSubMessage, ValueFieldDescriptor); // map单个元素中的value赋值	 
    ReflectionInstance->AddAllocatedMessage(MessageInstance, TargetFieldDescriptor, MapMessageInstance); // 将单个元素赋值到map中
}

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦