How to use Delphi RTTI to get and set Record Values

陌路散爱 提交于 2019-11-30 00:48:29

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.

menjaraz

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 ;
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!