RTTI & Attributes
Run-Time Type Information lets a program inspect types at run time: class names, published properties, enumeration names, method addresses, and (in extended RTTI) fields, methods, and attributes.
33.1 What is RTTI?
Run-Time Type Information lets a program inspect types at run time: class names, published properties, enumeration names, method addresses, and (in extended RTTI) fields, methods, and attributes. It powers the form designer, .lfm/.dfm streaming, data binding, serialization libraries, ORMs, and test frameworks.
Classic (published members, enums, sets) Extended (all visibility levels, methods, invoke) Delphi 2010+; FPC trunk (partial) System.Rtti (Delphi), Rtti (FPC)
Delphi 2010+; FPC trunk with {$modeswitch prefixedattributes}
33.2 Classic RTTI with TypInfo (Delphi and FPC)
(In Delphi the type names read string and Integer.)
program PublishedRtti;
{$mode objfpc}{$H+}
uses SysUtils, Variants, TypInfo;
type
{$M+} // generate RTTI for published members
TPerson = class
private
FName: string;
FAge: Integer;
FActive: Boolean;
published
property Name: string read FName write FName;
property Age: Integer read FAge write FAge;
property Active: Boolean read FActive write FActive;
end;
{$M-}
var
P: TPerson;
Props: PPropList;
Count, I: Integer;
begin
P := TPerson.Create;
try
SetPropValue(P, 'Name', 'Ada'); // set by name (Variant-based)
SetOrdProp(P, 'Age', 36);
SetEnumProp(P, 'Active', 'True');
Count := GetPropList(P, Props);
try
for I := 0 to Count - 1 do
Writeln(Props^[I]^.Name, ' : ', Props^[I]^.PropType^.Name,
' = ', GetPropValue(P, Props^[I]^.Name));
finally
FreeMem(Props);
end;
finally
P.Free;
end;
end.Name : AnsiString = Ada
Age : LongInt = 36
Active : Boolean = True33.3 Extended RTTI (Delphi)
By default Delphi generates extended RTTI for public and published properties and methods, and for all fields; {$RTTI EXPLICIT ...} changes this (often used to shrink executables).
uses System.Rtti;
procedure DumpObject(Obj: TObject);
var
Ctx: TRttiContext;
T: TRttiType;
Prop: TRttiProperty;
M: TRttiMethod;
begin
Ctx := TRttiContext.Create;
T := Ctx.GetType(Obj.ClassType);
Writeln('Type: ', T.Name);
for Prop in T.GetProperties do
if Prop.IsReadable then
Writeln(' ', Prop.Name, ' = ', Prop.GetValue(Obj).ToString);
for M in T.GetDeclaredMethods do
Writeln(' method ', M.Name);
M := T.GetMethod('Describe');
if Assigned(M) then
Writeln(M.Invoke(Obj, []).ToString); // dynamic invocation
end;33.4 Custom attributes (Delphi)
The Attribute suffix can be omitted when applying ([MaxLength(40)]). Attributes are used by DUnitX ([Test]), JSON serializers ([JSONName('id')]), ORMs ([Table('customers')]), and REST frameworks.
uses System.Rtti, System.SysUtils;
type
MaxLengthAttribute = class(TCustomAttribute)
private
FLength: Integer;
public
constructor Create(ALength: Integer);
property Length: Integer read FLength;
end;
RequiredAttribute = class(TCustomAttribute);
TCustomer = class
private
FName: string;
FEmail: string;
public
[Required, MaxLength(40)]
property Name: string read FName write FName;
[MaxLength(80)]
property Email: string read FEmail write FEmail;
end;
constructor MaxLengthAttribute.Create(ALength: Integer);
begin
inherited Create;
FLength := ALength;
end;
function Validate(Obj: TObject): TArray<string>;
var
Ctx: TRttiContext;
Prop: TRttiProperty;
Attr: TCustomAttribute;
S: string;
begin
Result := nil;
for Prop in Ctx.GetType(Obj.ClassType).GetProperties do
begin
S := Prop.GetValue(Obj).AsString;
for Attr in Prop.GetAttributes do
if (Attr is RequiredAttribute) and (S = '') then
Result := Result + [Prop.Name + ' is required']
else if (Attr is MaxLengthAttribute) and
(S.Length > MaxLengthAttribute(Attr).Length) then
Result := Result + [Format('%s exceeds %d charact
…