Attribute zur Laufzeit extrahieren
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;