Delphi 从指向记录类型rtti字段的指针获取值
我在使用Delphi的RTTI访问记录数据中记录类型的指针时遇到了麻烦 请检查我一直在处理的示例代码Delphi 从指向记录类型rtti字段的指针获取值,delphi,delphi-xe2,rtti,delphi-xe3,Delphi,Delphi Xe2,Rtti,Delphi Xe3,我在使用Delphi的RTTI访问记录数据中记录类型的指针时遇到了麻烦 请检查我一直在处理的示例代码 // Dummy Header typDummyHeader = ^tysDummyHeader; tysDummyHeader = record MessageCode : Integer; MessageLength : Integer; end; // Dummy record having header and trailer tysDummyR
// Dummy Header
typDummyHeader = ^tysDummyHeader;
tysDummyHeader = record
MessageCode : Integer;
MessageLength : Integer;
end;
// Dummy record having header and trailer
tysDummyRecord = record
Header : tysDummyHeader;
BotAmount : Double;
SoldAmount : Double;
SoldQty : Int64;
BotQty : Int64;
Tailer : typDummyHeader; // pointer to Dummy Header
end;
TclDummy = class
class function GetFieldValue<T>(const pipInstance : Pointer;
const piclField : TRttiField) : string;
class function ParseAndReturnString<T>(piclObject : T) : string;
end;
var
frmRTTITest: TfrmRTTITest;
implementation
{$R *.dfm}
procedure TfrmRTTITest.FormCreate(Sender: TObject);
var
losDummyRecord : tysDummyRecord;
begin
FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
losDummyRecord.Header.MessageCode := 5000;
losDummyRecord.Header.MessageLength := 54433;
losDummyRecord.BotAmount := 19.45;
losDummyRecord.SoldAmount := 34.22;
losDummyRecord.SoldQty := 102;
losDummyRecord.BotQty := 334;
losDummyRecord.Tailer := @losDummyRecord.Header;
ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
end;
class function TclDummy.GetFieldValue<T>(const pipInstance : Pointer;
const piclField : TRttiField) : string;
begin
case piclField.FieldType.TypeKind of
tkFloat: Result := FloatToStr(piclField.GetValue(pipInstance).AsExtended);
tkInt64: Result := IntToStr(piclField.GetValue(pipInstance).AsInt64);
tkInteger: Result := IntToStr(piclField.GetValue(pipInstance).AsInteger);
tkString: Result := Trim(piclField.GetValue(pipInstance).AsString);
end;
end;
class function TclDummy.ParseAndReturnString<T>(piclObject : T) : string;
var
losContext : TRttiContext;
losContextType : TRttiType;
loclField : TRttiField;
losRecordRTTI : TRttiRecordType;
loclRecordField : TRttiField;
losPointerType : TRttiPointerType;
losValue : TValue;
begin
Result := EmptyStr;
losContext := TRttiContext.Create;
losContextType := losContext.GetType(TypeInfo(T));
if losContextType.TypeKind = tkRecord then
begin
for loclField in losContextType.GetFields do
begin
case loclField.FieldType.TypeKind of
tkRecord:
begin
losRecordRTTI := loclField.FieldType.AsRecord;
for loclRecordField in losRecordRTTI.GetFields do
begin
Result := Result + '|' + GetFieldValue<T>(Addr(piclObject), loclRecordField);
end;
end; // tkRecord
tkPointer:
begin
losPointerType := loclField.FieldType as TRttiPointerType;
// Check only record type pointers.
if losPointerType.ReferredType.TypeKind = tkRecord then
begin
losValue := loclField.GetValue(Addr(piclObject));
if (not losValue.IsEmpty) then
begin
for loclRecordField in losPointerType.ReferredType.GetFields do
begin
// Result := Result + '|' + ???????????
end;
end;
end;
end; // tkPointer
else
Result := Result + '|' + GetFieldValue<T>(Addr(piclObject), loclField);
end;
end;
end;
losContext.Free;
end;
//伪头
typDummyHeader=^tysDummyHeader;
tysDummyHeader=记录
MessageCode:整数;
MessageLength:整数;
结束;
//具有头和尾的虚拟记录
tysDummyRecord=记录
标题:tysDummyHeader;
金额:双倍;
索尔达蒙特:双倍;
SoldQty:Int64;
数量:Int64;
Tailer:typDummyHeader;//指向伪标题的指针
结束;
TclDummy=class
类函数GetFieldValue(const pipInstance:指针;
常量piclField:TRttiField):字符串;
类函数ParseAndReturnString(piclObject:T):string;
结束;
变量
frmRTTITest:TFRMRTITEST;
实施
{$R*.dfm}
过程TfrmRTTITest.FormCreate(发送方:TObject);
变量
losDummyRecord:tysDummyRecord;
开始
FillChar(losDummyRecord,SizeOf(tysDummyRecord),0);
losDummyRecord.Header.MessageCode:=5000;
losDummyRecord.Header.MessageLength:=54433;
losDummyRecord.BotAmount:=19.45;
losDummyRecord.SoldAmount:=34.22;
losDummyRecord.SoldQty:=102;
losDummyRecord.BotQty:=334;
losDummyRecord.Tailer:=@losDummyRecord.Header;
ShowMessage(tclsdummy.ParseAndReturnString(losdumyRecord));
结束;
类函数tclsdummy.GetFieldValue(const pipInstance:Pointer;
常量piclField:TRttiField):字符串;
开始
case piclField.FieldType.TypeKind of
tkFloat:Result:=FloatToStr(piclField.GetValue(pipInstance.AsExtended);
tkInt64:Result:=IntToStr(piclField.GetValue(pipInstance.AsInt64);
tkInteger:Result:=IntToStr(piclField.GetValue(pipInstance.AsInteger));
tkString:Result:=Trim(piclField.GetValue(pipInstance.AsString);
结束;
结束;
类函数tclmdummy.ParseAndReturnString(piclObject:T):string;
变量
losContext:TRttiContext;
losContextType:TrtType;
loclField:TRttiField;
losRecordRTTI:TRttiRecordType;
loclRecordField:TRttiField;
losPointerType:TrtPointerType;
losValue:TValue;
开始
结果:=EmptyStr;
losContext:=TRttiContext.Create;
losContextType:=losContext.GetType(TypeInfo(T));
如果losContextType.TypeKind=tkRecord,则
开始
对于losContextType.GetFields中的loclField
开始
case loclField.FieldType.TypeKind of
tkRecord:
开始
losRecordRTTI:=loclField.FieldType.AsRecord;
对于losRecordRTTI.GetFields中的loclRecordField
开始
结果:=Result+'|'+GetFieldValue(Addr(piclObject),loclRecordField);
结束;
完tkRecord
tkPointer:
开始
losPointerType:=loclField.FieldType作为TrtPointerType;
//只检查记录类型指针。
如果losPointerType.ReferredType.TypeKind=tkRecord,则
开始
losValue:=loclField.GetValue(Addr(piclObject));
如果(不是losValue.IsEmpty),那么
开始
对于losPointerType.ReferredType.GetFields中的loclRecordField
开始
//结果:=结果+'|'+???????????
结束;
结束;
结束;
完TK指针
其他的
结果:=Result+'|'+GetFieldValue(Addr(piclObject),loclField);
结束;
结束;
结束;
losscontext.Free;
结束;
在上面的示例中,当字段是指向记录类型的tkPointer
时,如何从中读取值?Result:=Result+'|'+GetFieldValue(Addr(piclObject),loclRecordField);
Result := Result + '|' + GetFieldValue<T>(Addr(piclObject),loclRecordField);
我应该做这项工作。对不起,我的英语很差 @bummi的答案有效,但不正确 这取决于使用情况 如果使用下一个代码,则所有代码都可以正常工作:
var
losDummyRecord : tysDummyRecord;
begin
FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
losDummyRecord.Header.MessageCode := 5000;
losDummyRecord.Header.MessageLength := 54433;
losDummyRecord.BotAmount := 19.45;
losDummyRecord.SoldAmount := 34.22;
losDummyRecord.SoldQty := 102;
losDummyRecord.BotQty := 334;
losDummyRecord.Tailer := @losDummyRecord.Header;
ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
var
losDummyRecord:tysDummyRecord;
开始
FillChar(losDummyRecord,SizeOf(tysDummyRecord),0);
losDummyRecord.Header.MessageCode:=5000;
losDummyRecord.Header.MessageLength:=54433;
losDummyRecord.BotAmount:=19.45;
losDummyRecord.SoldAmount:=34.22;
losDummyRecord.SoldQty:=102;
losDummyRecord.BotQty:=334;
losDummyRecord.Tailer:=@losDummyRecord.Header;
ShowMessage(tclsdummy.ParseAndReturnString(losdumyRecord));
但如果您使用此代码,解析将无法正常工作:
var
losDummyRecord : tysDummyRecord;
ExternalHeaderVar: tysDummyHeader;
begin
ExternalHeaderVar.MessageCode := 23;
ExternalHeaderVar.MessageLength := 25;
FillChar(losDummyRecord, SizeOf(tysDummyRecord), #0);
losDummyRecord.Header.MessageCode := 5000;
losDummyRecord.Header.MessageLength := 54433;
losDummyRecord.BotAmount := 19.45;
losDummyRecord.SoldAmount := 34.22;
losDummyRecord.SoldQty := 102;
losDummyRecord.BotQty := 334;
losDummyRecord.Tailer := @ExternalHeaderVar;
ShowMessage(TclDummy.ParseAndReturnString<tysDummyRecord>(losDummyRecord));
var
losDummyRecord:tysDummyRecord;
外部头服务器:tysDummyHeader;
开始
ExternalHeaderVar.MessageCode:=23;
ExternalHeaderVar.MessageLength:=25;
FillChar(losDummyRecord,SizeOf(tysDummyRecord),0);
losDummyRecord.Header.MessageCode:=5000;
losDummyRecord.Header.MessageLength:=54433;
losDummyRecord.BotAmount:=19.45;
losDummyRecord.SoldAmount:=34.22;
losDummyRecord.SoldQty:=102;
losDummyRecord.BotQty:=334;
losDummyRecord.Tailer:=@ExternalHeaderVar;
ShowMessage(tclsdummy.ParseAndReturnString(losdumyRecord));
解决方案简单,在这两种情况下都能很好地工作,并可防止将来使用时出现意外错误:
tkPointer:
begin
losPointerType := loclField.FieldType as TRttiPointerType;
// Check only record type pointers.
if losPointerType.ReferredType.TypeKind = tkRecord then
begin
losValue := loclField.GetValue(Addr(piclObject));
if (not losValue.IsEmpty) then
begin
losValue.ExtractRawDataNoCopy(@NativeIntVar);
for loclRecordField in losPointerType.ReferredType.GetFields do
begin
Result := Result + '|' + GetFieldValue<T>(Pointer(NativeIntVar),loclRecordField);
end;
end;
end;
end; // tkPointer
tkPointer:
开始
losPointerType:=loclField.FieldType作为TrtPointerType;
//只检查记录类型指针。
如果losPointerType.ReferredType.TypeKind=tkRecord,则
开始
losValue:=loclField.GetValue(Addr(piclObject));
如果(不是losValue.IsEmpty),那么
开始
losValue.ExtractRawDataNoCopy(@NativeIntVar);
对于losPointerType.ReferredType.GetFields中的loclRecordField
开始
结果:=Result+'|'+GetFieldValue(指针(NativeIntVar),LocalRecordField);
结束;
结束;
结束;
完TK指针
基本上,我想做的是得到一个字符串co