Attribute zur Laufzeit extrahieren

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Attribute (RTTI)

Enthält Informationen über Laufzeitaspekte von Attributen: wie sie extrahiert werden und wie Entscheidungen aufgrund ihres Informationswertes getroffen werden.

Attributinstantiierung

Die Annotation (wie unter Hinweise zu Typen und Membern hinzufügen) ist eine einfache Methode zum Beifügen eines Attributs zu einem Typ oder einem Member. Die Informationen in der compilierten Binärdatei enthalten die Klasse des Attributs, den Zeiger auf den ausgewählten Konstruktor und die Liste der Konstanten, die bei der Instantiierung an den Konstruktor des Attributs übergeben werden.

Die tatsächliche Instantiierung von Attributen findet statt, wenn der Anwendungscode die Attribute in einem gegebenen Typ oder Typ-Member abfragt. Das bedeutet, dass Instanzen der Attributklassen nicht automatisch erstellt werden, sondern erst wenn das Programm explizit danach sucht. Es gibt weder eine feste Reihenfolge, in der Attribute instantiiert werden, noch ist bekannt, wie viele Instanzen erstellt werden. Ein Programm sollte davon nicht abhängen.

Beachten Sie die folgende Attributdeklaration:

type
  TSpecialAttribute = class(TCustomAttribute)
  public
    FValue: String;

    constructor Create(const AValue: String);
  end;

constructor TSpecialAttribute.Create(const AValue: String);
begin
  FValue := AValue;
end;

TSpecialAttribute wird dann im folgenden Beispiel als Annotation verwendet:

type
  [TSpecialAttribute('Hello World!')]
  TSomeType = record
  ...
  end;

Um das Attribut aus dem Typ TSomeType zu extrahieren, muss der Benutzercode die in der Unit System.Rtti bereitgestellte Funktionalität verwenden. Das folgende Beispiel zeigt den Code zum Extrahieren:

var
  LContext: TRttiContext;
  LType: TRttiType;
  LAttr: TCustomAttribute;
begin
  { Einen neuen Rtti-Kontext erstellen }
  LContext := TRttiContext.Create
  
  { Typinformationen für den Typ TSomeType extrahieren }
  LType := LContext.GetType(TypeInfo(TSomeType));

  { Nach dem benutzerdefinierten Attribut suchen und Verarbeitung ausführen } 
  for LAttr in LType.GetAttributes() do 
    if LAttr is TSpecialAttribute then 
      WriteLn(TSpecialAttribute(LAttr).FValue);
 
  { Kontext freigeben }
  LContext.Free;
end;

Wie in dem Beispiel gezeigt, muss der Benutzer speziellen Quelltext zum Abfragen auf Attributannotationen für einen Typ schreiben. Die eigentlichen Attributinstanzen werden in der Methode TRttiType.GetAttributes erstellt. Beachten Sie bitte, dass das Beispiel die Instanzen nicht freigibt; TRttiContext gibt anschließend alle Ressourcen frei.

Exceptions

Weil die eigentliche Instantiierung von Attributen im Benutzercode durchgeführt wird, könnten Exceptions in den Attributkonstruktoren auftreten. Die allgemeine Empfehlung ist, den Code, der auf Attribute abfragt, in eine try .. except-Klausel einzuschließen.

Um das Problem zu veranschaulichen, wurde der Attributkonstruktor im Originalbeispiel folgendermaßen geändert:

constructor TSpecialAttribute.Create(const AValue: String);
begin
  if AValue = '' then
    raise EArgumentException.Create('Expected a non-null string');

  FValue := AValue;
end;

und die Annotation für TSomeType wurde so geändert, dass ein leerer String an den Attributkonstruktor übergeben wird:

type
  [TSpecialAttribute('')]
  TSomeType = record
  ...
  end;

In diesem Fall schlägt der Code, der auf Attribute des Typs TSomeType abfragt, mit einer EArgumentException-Exception fehl, die von dem instantiierenden Attribut ausgelöst wird. Daher sollte der Abfragecode mit einer try .. except-Klausel versehen werden:

  { Nach dem benutzerdefinierten Attribut suchen und Verarbeitung ausführen } 
  try
     for LAttr in LType.GetAttributes() do
       if LAttr is TSpecialAttribute then 
         WriteLn(TSpecialAttribute(LAttr).FValue);
  except
    { ... Hier etwas ausführen ... }
  end;

Siehe auch