RTTI, Attributes and Reflection
25.1 Extended RTTI (System.Rtti)
{$RTTI EXPLICIT METHODS([vcPublic]) PROPERTIES([vcPublic, vcPublished]) FIELDS([vcPrivate])} controls how much RTTI is generated (affects binary size).
uses System.Rtti, System.TypInfo;
var Ctx := TRttiContext.Create; // record; TRttiContext.Create is optional in newer versions
var T := Ctx.GetType(TCustomer);
Writeln(T.Name, ' ', T.QualifiedName);
for var Prop in T.GetProperties do
Writeln(Prop.Name, ': ', Prop.PropertyType.Name, ' (', Prop.Visibility.ToString, ')');
for var M in T.GetMethods do
Writeln(M.Name);
var Cust := TCustomer.Create;
T.GetProperty('Name').SetValue(Cust, 'Ana');
Writeln(T.GetProperty('Name').GetValue(Cust).AsString);
T.GetMethod('Activate').Invoke(Cust, []);
var V: TValue := 42;
Writeln(V.AsInteger, ' ', V.IsType<Integer>, ' ', V.TypeInfo.Name);
V := TValue.From<TPoint>(Point(1, 2));25.2 Custom Attributes
Real-world uses: ORMs (Aurelius, mORMot, DORM), JSON serializers (REST.Json [JSONName], [JSONMarshalled(False)]), validation frameworks, DUnitX test attributes ([Test], [TestCase]), REST routing in RAD Server/Horse, dependency injection ([Inject] in Spring4D).
type
TableAttribute = class(TCustomAttribute)
private
FName: string;
public
constructor Create(const AName: string);
property Name: string read FName;
end;
ColumnAttribute = class(TCustomAttribute)
private
FName: string;
FRequired: Boolean;
public
constructor Create(const AName: string; ARequired: Boolean = False);
property Name: string read FName;
property Required: Boolean read FRequired;
end;
[Table('customers')]
TCustomer = class
private
FName: string;
FEmail: string;
published
[Column('customer_name', True)]
property Name: string read FName write FName;
[Column('email')]
property Email: string read FEmail write FEmail;
end;
function BuildInsertSQL(AClass: TClass): string;
begin
var Ctx := TRttiContext.Create;
var T := Ctx.GetType(AClass);
var Table := T.GetAttribute<TableAttribute>; // helper available in newer versions
var Cols: TArray<string>;
for var P in T.GetProperties do
for var A in P.GetAttributes do
if A is ColumnAttribute then
Cols := Cols + [ColumnAttribute(A).Name];
Result := Format('INSERT INTO %s (%s) VALUES (...)', [Table.Name, string.Join(
…25.3 Old-Style RTTI (TypInfo)
GetPropInfo, GetPropValue/SetPropValue, GetEnumName, GetOrdProp, IsPublishedProp. Used by DFM streaming and the Object Inspector for published members.