【问题标题】:Delphi RTTI: Get property's classDelphi RTTI:获取属性的类
【发布时间】:2012-07-06 05:24:39
【问题描述】:

使用 Delphi 2010 和 RTTI,我知道如何获取对象的类类型以及如何获取/设置对象属性的值和类型,但是如何确定属性来自继承链中的哪个类?我想以不同于主类的方式使用基类的属性。

考虑这段代码:

TClassBase = class(TObject)
published
  property A: Integer;
end;

TClassDescendant = class(TClassBase)
published
  property B: Integer;
end;

procedure CheckProperties(Obj: TObject);
var
  ctx: TRttiContext;
  objType: TRttiType;
  Prop: TRttiProperty;
begin
  ctx := TRttiContext.Create;
  objType := ctx.GetType(Obj.ClassInfo);
  for Prop in objType.GetProperties do begin
    if Prop.GetClassType is TClassBase then
      // do something special with base class properties
    else
      // standard functionality on all other properties
  end;
end;

问题是属性没有 GetClassType。 ClassType 只返回 TRttiInstancePropertyEx 而不是属性所属的类的名称。

【问题讨论】:

  • 你的问题有点混乱。请清除。你到底在找什么?您是否试图确定 Obj.PropertyName 返回的对象是 TClassBase 实例还是 TClassDescendant 实例?或者您是否试图确定Obj.PropertyName 本身是否被声明为TClassBase 而不管返回的对象实例实现什么类类型?您正在检查的对象如何使用TClassBaseTClassDescendant
  • 我想知道“你如何确定属性来自继承链中的哪个类”或者更确切地说是 TClassBase 或 TClassDescendant 中的属性。当我遍历一个类的属性时,我想忽略基类属性。在我的特殊情况下,我从 TInterfacedObject 继承了一个类,并对所有属性执行函数,除非它们具有 [Ignore] 属性,但我也想轻松忽略 TInterfacedObject 中的 RefCount。
  • 与其检查当前属性是否存在于特定类中,不如检查被枚举的对象是否是预期的类更有意义。这将更容易实施并且更准确。
  • @RemyLebeau,不,我正在使用 TClassDescendant 并遍历它的属性,但由于它继承了 TClassBase,因此它带来了这些属性。在查看所有属性时,我不知道如何确定属性属于哪个类。我需要忽略 TInterfacedObject 中声明的所有属性。

标签: delphi properties delphi-2010 rtti


【解决方案1】:

另一个选项是使用TRttiPropertyParent 属性,从这里您可以访问该属性所属的类。

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Rtti,
  SysUtils;

type
  TClassBase = class(TObject)
    private
      FA: Integer;
   published
    property A: Integer read FA;
  end;

  TClassDescendant = class(TClassBase)
    private
      FB: Integer;
    published
    property B: Integer read FB;
  end;

procedure CheckProperties(Obj: TObject);
var
  ctx: TRttiContext;
  objType: TRttiType;
  Prop: TRttiProperty;
begin
  ctx := TRttiContext.Create;
  objType := ctx.GetType(Obj.ClassInfo);
   for Prop in objType.GetProperties do
   if TRttiInstanceType(Prop.Parent).MetaclassType=TClassBase then
     Writeln(Format('The property %s is declarated in the TClassBase class',[Prop.Name]))
   else
     Writeln(Format('The property %s is not declarated in the TClassBase class',[Prop.Name]))
end;


begin
  try
   //CheckProperties(TClassBase.Create);
   CheckProperties(TClassDescendant.Create);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

【讨论】:

  • 完美!正是我需要的,只是不知道如何到达那里。谢谢。
【解决方案2】:

我不知道是否可以获取引入属性的类,但是您可以使用常规 RTTI 解决您的问题:

begin
  ...

  for Prop in objType.GetProperties do begin
    if Assigned(GetPropInfo(TClassBase, Prop.Name)) then
      // do something special with base class properties
    else
      // standard functionality on all other properties
  end;
end;

【讨论】:

  • 我认为这与用户要求的不同。您正在检查 TClassBase 类本身以查看它是否具有给定属性,但我认为用户正在询问如何检查另一个类的属性是 TClassBase 实例还是后代实例。
  • @Remy - 问题中的假设代码检查是否已在TClassBase 中引入了枚举属性。至少我是这么理解的。不过你可能说得很好..
【解决方案3】:

您可以使用GetDeclaredProperties 方法获取在当前类中声明的属性,然后与GetProperties 方法返回的值进行比较。

试试这个示例。

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Rtti,
  SysUtils;

type
  TClassBase = class(TObject)
    private
      FA: Integer;
   published
    property A: Integer read FA;
  end;

  TClassDescendant = class(TClassBase)
    private
      FB: Integer;
    published
    property B: Integer read FB;
  end;

procedure CheckProperties(Obj: TObject);

  function ExistProp(const PropName:string; List:TArray<TRttiProperty>) : Boolean;
  var
   Prop: TRttiProperty;
  begin
   result:=False;
    for Prop in List do
     if SameText(PropName, Prop.Name) then
     begin
       Result:=True;
       break;
     end;
  end;

var
  ctx: TRttiContext;
  objType: TRttiType;
  Prop: TRttiProperty;
  CurrentClassProps : TArray<TRttiProperty>;
begin
  ctx := TRttiContext.Create;
  objType := ctx.GetType(Obj.ClassInfo);
  CurrentClassProps:=objType.GetDeclaredProperties;
   for Prop in objType.GetProperties do
   if ExistProp(Prop.Name, CurrentClassProps) then
     Writeln(Format('The property %s is declarated in the current %s class',[Prop.Name, obj.ClassName]))
   else
     Writeln(Format('The property %s is declarated in the base class',[Prop.Name]))
end;



begin
  try
   //CheckProperties(TClassBase.Create);
   CheckProperties(TClassDescendant.Create);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

【讨论】:

  • 是的,我可以看到它是如何工作的——这是很长的路要走。
猜你喜欢
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多