Zkoušel jsem si hrát s RTTI (Run Time Type Information) a byl jsem tak nadšen jednoduchostí použití, že výsledkem je jednoduchý program, který ve stromě zobrazuje známé typy včetně metod, property a polí. Zároveň ukazuje efektivní použití anonymních metod, generických typů a to vše na 100 řádcích včetně deklarace.
Mějme formulář s TTreeView zarovnaným na celou plochu. V kódu formuláře bude následující kód.
unit Unit1;
interface
uses
Forms, StdCtrls, ComCtrls, Classes, Controls, Generics.Defaults;
type
TForm1 = class(TForm)
tv1: TTreeView;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure mFillTree;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
SysUtils, Rtti, Generics.Collections, TypInfo;
procedure TForm1.FormCreate(Sender: TObject);
begin
tv1.Items.BeginUpdate;
try
mFillTree;
finally
tv1.Items.EndUpdate;
end;
end;
procedure TForm1.mFillTree;
var
ctx: TRttiContext;
t: TRttiType;
oNode, oTempNode: TTreeNode;
arTypes: TArray<Rtti.TRttiType>;
cmp:TDelegatedComparer<Rtti.TRttiType>;
arMethods: TArray<TRttiMethod>;
m: TRttiMethod;
p: TRttiProperty;
f: TRttiField;
begin
ctx:= TRttiContext.Create;
try
// ziskej všechny zname typy
arTypes := ctx.GetTypes;
// comparator za pomocí anonymní metody
cmp := TDelegatedComparer<Rtti.TRttiType>.Create(
function (const Left, Right: TRttiType): Integer
begin
Result := AnsiCompareStr(Left.QualifiedName, Right.QualifiedName);
end);
// sort za pomoci vytvořeného porovnávače podle jmen
TArray.Sort<Rtti.TRttiType>(arTypes, cmp);
cmp.Free;
// seřazené typy projdi přes for in do
for t in arTypes do
begin
// uzel ve stromu pro typ
oNode:= tv1.Items.AddChild(nil, t.QualifiedName);
// poduzel pro metody
oTempNode := tv1.Items.AddChild(oNode, 'metody');
for m in t.GetMethods do
tv1.Items.AddChild(oTempNode, m.ToString);
// poduzel pro property
oTempNode := tv1.Items.AddChild(oNode, 'property');
for p in t.GetProperties do
tv1.Items.AddChild(oTempNode, p.ToString);
// poduzel pro pole
oTempNode := tv1.Items.AddChild(oNode, 'pole');
for f in t.GetFields do
tv1.Items.AddChild(oTempNode, f.ToString);
end;
finally
ctx.Free;
end;
end;
end.
Pěkná konstrukce je od řádku 58, kdy používáme obecný porovnávač (jeden z několika možných), ale vlastní implementace porovnávání je pomocí anonymní metody.
Deklarace TDelegatedComparer je v jednotce Generics.Defaults a vypadá takto (TDelegatedComparer je jen jedna z možností):
TComparison<T> = reference to function(const Left, Right: T): Integer;
TDelegatedComparer<T> = class(TComparer<T>)
private
FCompare: TComparison<T>;
public
constructor Create(const ACompare: TComparison<T>);
function Compare(const Left, Right: T): Integer; override;
end;
Zbytek kódu je podle mne jasný a přímočarý, případné dotazy do komentářů. Jo a pro kompilaci je nutné Delphi 2010 a vyšší.