2012-07-05 39 views
5

使用Delphi 2010和RTTI,我知道如何获取对象的类类型以及如何获取/设置对象属性的值和类型,但是如何确定对象的属性值继承链属性从何而来?我想要使​​用与主类不同的基类的属性。Delphi 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而不是属性所属类的名称。

+1

你的问题有点混乱。请澄清。你在找什么?你是否试图确定'Obj.PropertyName'是否返回一个'TClassBase'实例与一个'TClassDescendant'实例的对象?或者你是否试图确定'Obj.PropertyName'本身是否被声明为'TClassBase',而不管返回的对象实例实现什么类的类型?你正在检查的对象如何使用'TClassBase'和'TClassDescendant'? – 2012-07-05 20:55:32

+0

我想知道“你如何确定继承链中属性来自哪个类”或者更确切地说是TClassBase或TClassDescendant中的属性。当我遍历一个类的属性时,我想忽略基类的属性。在我的特殊情况下,我从TInterfacedObject继承了一个类,并在所有属性上执行一个函数,除非它们具有[Ignore]属性,但我也想轻松忽略来自TInterfacedObject的RefCount。 – 2012-07-05 22:59:03

+0

而不是检查当前属性是否存在于特定的类中,检查被枚举的对象是否为预期的类会更有意义。这将更容易实施,并且更准确。 – 2012-07-05 23:06:47

回答

5

另一种选择是使用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. 
+0

完美!正是我所需要的,只是不知道如何到达那里。谢谢。 – 2012-07-05 22:43:09

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; 
+0

我不认为这是做用户所要求的相同的事情。您正在检查TClassBase类本身以查看它是否具有给定属性,但我认为用户正在询问如何检查另一个类的属性是否是TClassBase实例或后代实例。 – 2012-07-05 20:43:21

+0

@Remy - 问题中的假设代码检查'TClassBase'中是否已经引入了枚举属性。至少这就是我所理解的。你可能会很好,但.. – 2012-07-05 20:48:23

+1

我只是试了一下,这也解决了这个问题。谢谢! – 2012-07-05 22:53:32

2

可以使用GetDeclaredProperties方法来获取属性在declarated当前类,然后与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. 
+0

是的,我可以看到如何工作 - 这是漫长的。 – 2012-07-05 22:45:05