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.