2012-07-05 26 views
5

Delphi 2010 ve RTTI kullanarak, bir nesnenin sınıf türünü ve bir nesnenin özelliklerinin türünü ve türünü nasıl elde edeceğinizi/ayarlayacağımı bilirim, ancak hangi sınıfın miras zinciri bir mülkten mi geldi? Bir ana sınıfın özelliklerini ana sınıftan farklı kullanmak istiyorum.Delphi RTTI: Özellik sınıfını alın

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; 

sorun özellikleri için hiçbir GetClassType yoktur geçerli:

bu kodu düşünün. ClassType, mülkün ait olduğu sınıfın adı yerine, yalnızca TRttiInstancePropertyEx değerini döndürür.

+1

Sorunuz biraz kafa karıştırıcı. Lütfen ayrıl. Hangi EXACTLY arıyorsunuz? Obj.PropertyName ''TClassDescendant' örneğine karşı bir' TClassBase' örneği olan bir nesne döndürüp döndürmediğini belirlemeye mi çalışıyorsunuz? Yoksa, Obj.PropertyName öğesinin, döndürülmüş nesne örneğinin uyguladığı sınıf türünden bağımsız olarak "TClassBase" olarak bildirilmiş olup olmadığını belirlemeye mi çalışıyorsunuz? TClassBase' ve 'TClassDescendant' kontrol ettiğiniz nesne (ler) tarafından nasıl kullanılır? –

+0

"Miras zincirinde hangi sınıfın nereden geldiğini nasıl belirlersiniz" veya TClassBase veya TClassDescendant'daki özellikleri bilmek isterim. Bir sınıfın özelliklerini geçerken, temel sınıf özelliklerini göz ardı etmek istiyorum. Benim özel durumumda, TInterfacedObject'ten bir sınıf aldım ve [Ignore] özelliğine sahip olmadıkça tüm özelliklerde bir işlev yapıyorum, ancak aynı zamanda TInterfacedObject öğesinden RefCount'u da kolayca göz ardı etmek istiyorum. –

+0

Geçerli özelliğin belirli bir sınıfta var olup olmadığını kontrol etmek yerine, numaralandırılan nesnenin amaçlanan sınıf olup olmadığını kontrol etmek daha mantıklı olacaktır. Uygulanması ve daha doğru olması çok daha kolay olurdu. –

cevap

5

Başka bir seçenek de mülkiyet parçası olan sınıfa erişebilirsiniz buradan, TRttiProperty ait Parent özelliğini kullanmaktır.

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

Mükemmel! Tam olarak ihtiyacım olan şey, oraya nasıl gidileceğini bilmiyordu. Teşekkürler. –

2

bir özellik tanıtıldı sınıfını elde etmenin mümkün olmadığını bilmiyorum, ancak normal RTTI ile sorununuzu çözebilir:

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

Bunun, kullanıcının istediği şeyi yaptığını sanmıyorum. Belirli bir özelliği olup olmadığını görmek için TClassBase sınıfının kendisini denetliyorsunuz, ancak kullanıcının başka bir sınıfın bir özelliğinin bir TClassBase örneği mi yoksa bir alt öğe mi olduğunu kontrol etmesini istediğini düşünüyorum. –

+0

@Remy - Sorgudaki varsayımsal kod, sayılan bir özelliğin "TClassBase" 'te tanıtılmış olup olmadığını kontrol eder. En azından anladım. Yine de çok iyi olabilirsiniz .. –

+1

Sadece denedim ve bu da sorunu çözüyor. Teşekkürler! –

2

Sen GetDeclaredProperties yöntemi kullanabilirsiniz özellikleri de yardımıyla bildirilmektedir almak geçerli sınıf ve daha sonra GetProperties yöntemi tarafından döndürülen değerlerle karşılaştır.

Bu örnekte deneyin.

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

Evet, bunun nasıl olacağını görebiliyorum - bu uzun yol. –