一、前言
最近有个需求,需要在运行时去读写message。查阅资料之后,发现proto是支持反射的。可以利用反射完成这个需求。
二、Protobuf中的反射原理
反射原理的部分可以参考这篇文章:深入 ProtoBuf - 反射原理解析
反射使用的部分可以参考这篇文章:巧用 Protobuf 反射来优化代码,拒做 PB Boy和google 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 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中
}