Listando as propriedades de uma classe

Segue um código (pascal/Delphi) que criei para listar as propriedades que pertencem a uma classe.

O código usa a RTTI do Delphi para “percorrer” as propriedades. A procedure é recursiva, ou seja, se uma das propriedades for também um classe, a procedure chama ela mesma passando como parâmetro a classe da propriedade encontrada.

Para compilar o código abaixo, crie uma nova aplicação VCL e no form principal coloque um TMemo e um TButton, e configure os eventos conforme o código abaixo.

Substitua o segundo parâmetro da chamada a getPropList pela classe que deseja “vasculhar”. O terceiro parâmetro é o quão “profundo” você deseja ir em relação as iterações quando uma propriedade encontrada for uma classe.

Clique no botão e o Memo será preenchido com as propriedades da classe TButton, obtendo o seguinte resultado para um máximo de uma iteração:

Action
Align
Anchors
BiDiMode
Cancel
Caption
CommandLinkHint
Constraints
Default
DisabledImageIndex
DoubleBuffered
DragCursor
DragKind
DragMode
DropDownMenu
ElevationRequired
Enabled
Font
HotImageIndex
ImageAlignment
ImageIndex
ImageMargins
Images
ModalResult
ParentBiDiMode
ParentDoubleBuffered
ParentFont
ParentShowHint
PopupMenu
PressedImageIndex
SelectedImageIndex
ShowHint
Style
StylusHotImageIndex
TabOrder
TabStop
Visible
WordWrap
StyleElements

E para o máximo de 2 iterações:

Action
Action.ActionComponent
Align
Anchors
BiDiMode
Cancel
Caption
CommandLinkHint
Constraints
Constraints.MaxHeight
Constraints.MaxWidth
Constraints.MinHeight
Constraints.MinWidth
Default
DisabledImageIndex
DoubleBuffered
DragCursor
DragKind
DragMode
DropDownMenu
DropDownMenu.PopupComponent
DropDownMenu.PopupPoint
DropDownMenu.Alignment
DropDownMenu.AutoHotkeys
DropDownMenu.AutoLineReduction
DropDownMenu.AutoPopup
DropDownMenu.BiDiMode
DropDownMenu.HelpContext
DropDownMenu.Images
DropDownMenu.MenuAnimation
DropDownMenu.OwnerDraw
DropDownMenu.ParentBiDiMode
DropDownMenu.TrackButton
ElevationRequired
Enabled
Font
Font.FontAdapter
Font.Handle
Font.PixelsPerInch
Font.Charset
Font.Color
Font.Height
Font.Name
Font.Orientation
Font.Pitch
Font.Size
Font.Style
Font.Quality
HotImageIndex
ImageAlignment
ImageIndex
ImageMargins
ImageMargins.Left
ImageMargins.Top
ImageMargins.Right
ImageMargins.Bottom
Images
Images.Handle
Images.AllocBy
Images.BlendColor
Images.GrayscaleFactor
Images.BkColor
Images.DrawingStyle
Images.Height
Images.ImageType
Images.Masked
Images.ShareImages
Images.Width
Images.ColorDepth
ModalResult
ParentBiDiMode
ParentDoubleBuffered
ParentFont
ParentShowHint
PopupMenu
PopupMenu.PopupComponent
PopupMenu.PopupPoint
PopupMenu.Alignment
PopupMenu.AutoHotkeys
PopupMenu.AutoLineReduction
PopupMenu.AutoPopup
PopupMenu.BiDiMode
PopupMenu.HelpContext
PopupMenu.Images
PopupMenu.MenuAnimation
PopupMenu.OwnerDraw
PopupMenu.ParentBiDiMode
PopupMenu.TrackButton
PressedImageIndex
SelectedImageIndex
ShowHint
Style
StylusHotImageIndex
TabOrder
TabStop
Visible
WordWrap
StyleElements

Espero que seja útil para alguém 🙂

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    procedure getPropList(Base: string; Classe: TClass; MaxIterations: integer);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  System.RTTI;

var
  Ctx: TRttiContext;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Ctx := TRttiContext.Create;
  Memo1.Lines.Clear;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Ctx.free;
end;

function Formata(Base, s: string): string;
begin
  if Base <> '' then
    Result := Base + '.' + s
  else
    Result := s;
end;

procedure TForm1.getPropList(Base: string; Classe: TClass; MaxIterations: integer);
var
  T: TRttiType;
  P: TRttiProperty;
begin
  T := Ctx.GetType(Classe);
  for P in T.GetDeclaredProperties do
  begin
    if P.PropertyType.TypeKind = tkMethod then // Não queremos extrair os métodos
      continue;
    Memo1.Lines.Add(Formata(Base, P.Name));
    if (P.PropertyType.TypeKind = tkClass) and (P.Name <> 'Owner') and (P.Name <> 'Parent') then
    begin
      Dec(MaxIterations);
      if MaxIterations > 0 then
        getPropList(Formata(Base, P.Name), P.PropertyType.AsInstance.MetaclassType, MaxIterations);
      Inc(MaxIterations);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  getPropList('', TButton { Coloque a classe que deseja extrair as propriedades }, 2 {Qual o máximo de interações});
end;

end.