Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi RTTI: Get property's class

Using Delphi 2010 and RTTI, I know how to get the class type of an object and how to get/set the value and type of an object's properties, but how do you determine which class in the inheritance chain a property came from? I want to use the properties of a base class differently than the main class.

Consider this code:

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;

The problem is there is no GetClassType for the properties. ClassType just returns TRttiInstancePropertyEx instead of the name of the class to which the property belongs.

like image 509
David Cornelius Avatar asked Jul 05 '12 18:07

David Cornelius


2 Answers

You can use the GetDeclaredProperties method to get properties declarated in the current class and then compare against the values returned by the GetProperties method.

Try this sample.

{$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.
like image 185
RRUZ Avatar answered Nov 17 '22 21:11

RRUZ


I don't know if it's possible to get the class which a property was introduced, but you can solve your problem with regular 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;
like image 40
Sertac Akyuz Avatar answered Nov 17 '22 21:11

Sertac Akyuz