Get/Set sub properties ussing RTTI

前端 未结 2 654
轻奢々
轻奢々 2021-01-06 14:43

Given the following code snippet below, using GetPropValue(MyComponent,\'MySubComponent.Prop1\') raises an EPropertyError exception. How can I retrieve or set t

相关标签:
2条回答
  • 2021-01-06 14:55

    As Robert says the dot notation is not supported , but you can create easily a function to set or get a sub-property value using the RTTI. check this sample

    {$APPTYPE CONSOLE}
    
    uses
      Rtti,
      Classes,
      SysUtils;
    
    
    Type
      TMySubComponent = class(TInterfacedPersistent)
      private
        FProp1: Integer;
      published
        property Prop1: integer read FProp1 write FProp1;
      end;
    
      TMyComponent = class(TComponent)
      private
        FMySubComponent : TMySubcomponent;
      published
        property MySubComponent: TMySubComponent read FMySubComponent write FMySubComponent ;
      end;
    
    
    
    procedure SetObjValueEx(const ObjPath:string;AInstance:TObject;AValue:TValue);
    Var
     c            : TRttiContext;
     Prop         : string;
     SubProp      : string;
     pm           : TRttiProperty;
     p            : TRttiProperty;
     Obj          : TObject;
    begin
     Prop:=Copy(ObjPath,1,Pos('.',ObjPath)-1);
     SubProp:=Copy(ObjPath,Pos('.',ObjPath)+1);
     c := TRttiContext.Create;
     try
       for pm in c.GetType(AInstance.ClassInfo).GetProperties do
       if CompareText(Prop,pm.Name)=0 then
       begin
         p := c.GetType(pm.PropertyType.Handle).GetProperty(SubProp);
          if Assigned(p) then
          begin
            Obj:=pm.GetValue(AInstance).AsObject;
            if Assigned(Obj) then
              p.SetValue(Obj,AValue);
          end;
          break;
       end;
     finally
       c.Free;
     end;
    end;
    
    
    function GetObjValueEx(const ObjPath:string;AInstance:TObject):TValue;
    Var
     c            : TRttiContext;
     Prop         : string;
     SubProp      : string;
     pm           : TRttiProperty;
     p            : TRttiProperty;
     Obj          : TObject;
    begin
     Prop:=Copy(ObjPath,1,Pos('.',ObjPath)-1);
     SubProp:=Copy(ObjPath,Pos('.',ObjPath)+1);
     c := TRttiContext.Create;
     try
       for pm in c.GetType(AInstance.ClassInfo).GetProperties do
       if CompareText(Prop,pm.Name)=0 then
       begin
         p := c.GetType(pm.PropertyType.Handle).GetProperty(SubProp);
          if Assigned(p) then
          begin
            Obj:=pm.GetValue(AInstance).AsObject;
            if Assigned(Obj) then
              Result:=p.GetValue(Obj);
          end;
          break;
       end;
     finally
       c.Free;
     end;
    end;
    
    Var
      MyComp : TMyComponent;
    begin
      try
         MyComp:=TMyComponent.Create(nil);
         try
           MyComp.MySubComponent:=TMySubComponent.Create;
           //Set the value of the property 
           SetObjValueEx('MySubComponent.Prop1',MyComp,777);
           //Get the value of the property 
           Writeln(Format('The value of MySubComponent.Prop1 is %d',[GetObjValueEx('MySubComponent.Prop1',MyComp).AsInteger]));
         finally
           MyComp.Free;
         end;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    end.
    
    0 讨论(0)
  • 2021-01-06 15:09

    The dot notation you used in your question is not supported.

    You need to get the Value of the SubComponent, then perform the Set and Get on the individual properties.

    var
      C: TRttiContext;
      MyComp : TMyComponent;
      MyCompType : TRttiInstanceType;
      MySubCompType : TRttiInstanceType;
      MySubComponentValue : TValue;
    begin
      MyComp := TMyComponent.create(Self); 
      ...
      // RTTI.Pas Method
      MyCompType :=  c.GetType(TMyComponent.ClassInfo) as TRttiInstanceType;
      MySubCompType := c.GetType(TMySubComponent.ClassInfo) as TRttiInstanceType;
      MySubComponentValue := MyCompType.GetProperty('MySubComponent').GetValue(MyComp);
    
      if Not MySubComponentValue.IsEmpty then
      begin
          MySubCompType.GetProperty('Prop1').SetValue(MySubComponentValue.AsObject,43);
      end;
    
     //TypInfo.pas Method
     SubComp := GetObjectProp(MyComp,'MySubComponent');
     if Assigned(SubComp) then
     begin
        SetPropValue(SubComp,'Prop1',5);
        prop1Value := GetPropValue(SubComp,'Prop1');
     end;
    
    end;
    

    The TypInfo.pas method will only work with published properties, you can get the public properties with the RTTI.pas method.

    0 讨论(0)
提交回复
热议问题