I\'m attempting to use the enhanced RTTI features in Delphi XE or later, to read and write objects to XML. So far I\'ve been successful with integers, floats, strings, enum
I presume you are trying to save the value of a record-typed field of the runtime type of Self, yes?
You have to get the value of the field first, with FProp.GetValue(Self)
. Let's say you put that in a variable called FieldValue
of type TValue
. You can then save the fields of the record value as you wish, though you'll probably want to write a recursive procedure for it, as the fields of the record may themselves be fields. The field getter for records expects the address of the record (a pointer to its start) for symmetry with the setter; the setter expects the address rather than the value because otherwise there would be no easy way to modify a field "in situ" in another class or record, since records are otherwise passed around by value.
You could get that with FieldValue.GetReferenceToRawData
, which will return a pointer to the start of the records stored inside the TValue
.
Hopefully this gives you enough clues to continue.
Attribution: Originally posted as question's updates by the OP (Mitch ) - Migrated as separate answer to improve visibility.
Barry's solution did the trick. Here's the revised code:
tkRecord : begin
subchild := Child.Items.Add ( FProp.Name ) ;
Value := FProp.GetValue(self) ;
FRecord := FContext.GetType(FProp.GetValue(self).TypeInfo).AsRecord ;
for FField in FRecord.GetFields do begin
Data := FField.GetValue ( Value.GetReferenceToRawData ) ;
subchild.Items.Add ( FField.Name ).Value := Data.ToString ;
end;
end ;
For those that need to deal with arrays:
tkDynArray : begin
Value := FProp.GetValue ( self ) ;
FArray := FContext.GetType(Value.TypeInfo) as TRttiDynamicArrayType ;
subchild := child.Items.Add ( FProp.Name ) ;
cnt := Value.GetArrayLength ;
subchild.Properties.Add ( 'Count' , cnt ) ;
case FArray.ElementType.TypeKind of
tkInteger ,
tkFloat : begin
for a := 0 to cnt-1 do begin
Data := Value.GetArrayElement ( a ) ;
subchild.Items.Add ( IntToStr(a) , Data.ToString ) ;
end;
end ;
tkRecord : begin
FRecord := FArray.ElementType as TRttiRecordType ;
for a := 0 to cnt-1 do begin
Data := Value.GetArrayElement ( a ) ;
subsubchild := subchild.Items.Add ( IntToStr(a) ) ;
for FField in FRecord.GetFields do
SaveField ( subsubchild , FContext , FField , Data.GetReferenceToRawData ) ;
end;
end ;