使用 RTTI 获取/设置子属性

发布于 2024-12-08 01:33:37 字数 538 浏览 2 评论 0原文

根据下面的代码片段,使用 GetPropValue(MyComponent,'MySubComponent.Prop1') 会引发 EPropertyError 异常。 如何使用 GetPropValue / SetPropValue 检索或设置 SubProperties 的值?

Type
  TMySubComponent = class(TInterfacedPersitent)
  private
    FProp1: Integer;
  published
    property Prop1: integer read FProp1 write FProp1;
  end;

  TMyComponent = class(TCompoent)
  private
    FMySubComponent : TMySubcomponent; 
  published
    property MySubComponent: TMySubComponent read FMySubComponent write FMySubComponent ;
  end;

Given the following code snippet below, using GetPropValue(MyComponent,'MySubComponent.Prop1') raises an EPropertyError exception.
How can I retrieve or set the values of SubProperties using GetPropValue / SetPropValue?

Type
  TMySubComponent = class(TInterfacedPersitent)
  private
    FProp1: Integer;
  published
    property Prop1: integer read FProp1 write FProp1;
  end;

  TMyComponent = class(TCompoent)
  private
    FMySubComponent : TMySubcomponent; 
  published
    property MySubComponent: TMySubComponent read FMySubComponent write FMySubComponent ;
  end;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦旅人picnic 2024-12-15 01:33:37

正如 Robert 所说,不支持点符号,但您可以轻松创建一个函数来使用 RTTI 设置或获取子属性值。检查这个样本

{$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.

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.
孤云独去闲 2024-12-15 01:33:37

不支持您在问题中使用的点符号。

您需要获取子组件的值,然后对各个属性执行设置和获取。

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;

TypInfo.pas 方法仅适用于已发布的属性,您可以使用 RTTI.pas 方法获取公共属性。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文