Delphi RTTI:Get属性';s级

Delphi RTTI:Get属性';s级,delphi,properties,delphi-2010,rtti,Delphi,Properties,Delphi 2010,Rtti,使用Delphi2010和RTTI,我知道如何获取对象的类类型以及如何获取/设置对象属性的值和类型,但是如何确定属性来自继承链中的哪个类?我希望基类的属性与主类不同 考虑以下代码: TClassBase = class(TObject) published property A: Integer; end; TClassDescendant = class(TClassBase) published property B: Integer; end; procedure CheckP

使用Delphi2010和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,而不是属性所属的类的名称。

我不知道是否可以获取引入属性的类,但您可以使用常规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;
您可以使用该方法获取在当前类中声明的属性,然后与该方法返回的值进行比较

试试这个样品

{$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.
{$APPTYPE控制台}
{$R*.res}
使用
Rtti,
SysUtils;
类型
TClassBase=class(TObject)
私有的
FA:整数;
出版
属性A:整数读取FA;
结束;
TCLASSDENANT=类(TClassBase)
私有的
FB:整数;
出版
属性B:整数读取FB;
结束;
程序检查属性(对象:TObject);
函数ExistProp(constpropname:string;List:TArray):布尔;
变量
财产:信托财产;
开始
结果:=假;
对于列表中的道具,请执行以下操作:
如果是SameText(PropName,Prop.Name),那么
开始
结果:=真;
打破
结束;
结束;
变量
ctx:trtti上下文;
对象类型:trtti型;
财产:信托财产;
当前类道具:柏油;
开始
ctx:=TRttiContext.Create;
objType:=ctx.GetType(Obj.ClassInfo);
CurrentClassProps:=objType.GetDeclaredProperties;
对于objType.GetProperties中的Prop
如果ExistProp(Prop.Name,CurrentClassProps),则
Writeln(格式('属性%s在当前%s类中声明,[Prop.Name,obj.ClassName]))
其他的
Writeln(格式('属性%s在基类中声明',[Prop.Name]))
结束;
开始
尝试
//CheckProperties(TClassBase.Create);
CheckProperties(tclassDegenant.Create);
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
Readln;
结束。
另一个选项是使用的属性,从这里可以访问该属性所属的类

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

我不认为这是做同样的事情,用户要求。您正在检查TClassBase类本身,以查看它是否具有给定的属性,但我想用户是在问如何检查另一个类的属性是TClassBase实例还是后代实例。@Remy-问题中的假设代码检查是否已在
TClassBase
中引入枚举属性。至少我明白了。你可能是对的你的问题有点让人困惑。请澄清。你到底在找什么?您是否正在尝试确定
Obj.PropertyName
是否返回一个对象,该对象是
TClassBase
实例还是
tclasssgender
实例?或者,无论返回的对象实例实现的是什么类类型,您是否试图确定
Obj.PropertyName
本身是否声明为
TClassBase
?您正在检查的对象如何使用
TClassBase
tclassdesgent
?我想知道“如何确定属性来自继承链中的哪个类”,或者更确切地说是TClassBase或tclassdesgent中的属性。当我遍历一个类的属性时,我想忽略基类属性。在我的特殊情况下,我从TInterfacedObject派生了一个类,并且正在对所有属性执行一个函数,除非它们具有[Ignore]属性,但我还想轻松忽略TInterfacedObject的RefCount。而不是检查当前属性是否存在于特定类中,检查被枚举的对象是否是预期的类更有意义。这将更容易实现,也更准确。@RemyLebeau,不,我正在使用TclassDegenant并遍历它的属性,但由于它继承了TClassBase,所以它会将这些属性一起带来。在查看所有属性时,我不知道如何确定a类属性属于哪个类别。我需要忽略TInterfacedObject中声明的所有属性。太好了!正是我需要的,只是不知道怎么去。谢谢。是的,我知道这是怎么回事——这是一条很长的路。