Attribute ermöglichen auf deklarative Art und Weise die Zuweisungen von Metainformationen zu Programmeinheiten. Zur Entwicklungszeit können für verschiedene Programmeinheiten, zum Beispiel Methoden, Klassen, Schnittstellen usw., Attribute festgelegt werden. Ausgewertet werden die Attribute dann zur Kompilierungs- oder Laufzeit der Anwendung. Im Grunde handelt es sich bei Attributen um Anmerkungen zu Programmeinheiten, die sich je nach Attribut unterschiedlich auswirken. Manche Attribute haben Einfluss auf das Laufzeitverhalten, andere hingegen wirken sich nur zur Kompilierungszeit aus. Attribute werden auch verwendet, um strukturelle Informationen bereitzustellen, die dann extern verarbeitet werden können. Als Beispiel für strukturelle Informationen kann die Spezifikation einer Windows-Communication-Foundation-(WCF-)Schnittstelle genannt werden. Auch hierbei werden über Attribute die einzelnen Mitglieder (DataMember, OperationContract) definiert. Anschließend wird aus diesen zusätzlichen, über Attribute spezifizierten Informationen der vollständige WCF-Dienst abgeleitet. Weitere Informationen dazu sind auf MSDN zu finden.
Verwendung von Attributen
Das .NET Framework stellt schon einige Attributklassen bereit, die direkt verwendet werden können. Im oberen Abschnitt wurde bereits in Bezug auf WCF-Dienste ein Beispiel erläutert. Daneben existieren aber auch Attribute, die sich zur Kompilierungszeit auswirken. Die Klasse ObsoleteAttribute stellt ein Attribut bereit, um Programmeinheiten (Methoden, Klassen usw.) als veraltet zu markieren. Tritt der Compiler während der Kompilierzeit auf ein solches Attribut, wird eine entsprechende Warnung ausgegeben. Wie deutlich wurde, hat das ObsoleteAttribut keinen direkten Einfluss auf das Laufzeitverhalten, es werden lediglich Compiler-Warnungen generiert. Sollen hingegen bestimmte Programmeinheiten unter definierten Bedingungen ein verändertes Laufzeitzeitverhalten aufweisen, ist die Klasse ConditionalAttribute zu verwenden. Über dieses Attribut können Methoden spezifiziert werden, die nur unter bestimmten Kompilierungsbedingungen aufgerufen werden sollen. Die Festlegung erfolgt über ein Symbol, das den Kompilierungsstatus angibt. Das ermöglicht zum Beispiel, dass Protokolleinträge nur dann geschrieben werden, wenn es sich um eine Debug-Version handelt. Das ConditionalAttribute kann allerdings nur auf Methodenebene angewendet werden, andere Programmeinheiten können nicht ausgeblendet werden. Listing 1 zeigt, wie das Attribut eingesetzt werden kann. Standardmäßig ist bereits in jedem .NET-Projekt, wenn vielleicht auch nicht immer beachtet, eine Vielzahl an Attributen vorhanden. In der Datei AssemblyInfo, die zahlreiche Informationen zu dem Projekt enthält, werden die eigentlichen (Assembly-)Informationen über Attribute eingefügt. Neben den hier geschilderten Beispielen existieren darüber hinaus viele weitere Einsatzgebiete für Attribute.
Listing 1: Conditional Attribut
[ConditionalAttribute("DEBUG")] public static void DebugMessages(string msg) { Console.WriteLine(msg); } static void Main(string[] args) { DebugMessages("Hello world"); Console.WriteLine("Ready"); Console.ReadLine(); }
Custom Attributes
Neben der Verwendung von bereits vorhandenen Attributklassen, den so genannten Intrinsic Attributes, können auch für eigene Zwecke neue Attribute, einfach bezeichnet als Custom Attributes, definiert werden. Neu definierte Attributklassen müssen wie auch eingebaute Attributklassen von der abstrakten Klasse Attribute aus dem Namespace System ableiten. Ebenfalls sollte die vorgegebene Namenskonvention eingehalten werden. Sie besagt, dass dem eigentlichen Klassennamen das Suffix Attribute anzuhängen ist. Zusätzlich muss über ein Attribut definiert werden, für welche Programmeinheiten das neue Attribut zulässig ist. Das heißt nicht alle Attribute können überall verwendet werden. Die Festlegung, für welche Programmeinheiten ein Attribut anwendbar ist, erfolgt über das Attribut AttributeUsuage. Über die dort enthaltene Eigenschaft AttributeTargets kann festgelegt werden, für welche Ziele das jeweilige Attribut anwendbar ist. Tabelle 1 enthält eine Übersicht aller möglichen Ziele. Zusätzlich kann über die Eigenschaft AllowMultiple gesteuert werden, ob das Attribut nur einmal oder öfter angewendet werden kann.
Programmelement |
Verwendung |
All |
für alle Elemente anwendbar |
Bibliothek (Assembly) |
nur für Bibliotheken zulässig |
Klasse (Class) |
nur für Klassen zulässig |
Konstruktor (Constructor) |
nur für Konstruktoren zulässig |
Funktionszeiger (Delegate) |
nur für Funktionszeiger zulässig |
Aufzählung (Enum) |
nur für Aufzählungen zulässig |
Ereignis (Event) |
nur für Ereignisse zulässig |
Feld (Field) |
nur für Felder zulässig |
Schnittstelle (Interface) |
nur für Schnittstellen zulässig |
Methode (Method) |
nur für Methoden zulässig |
Modul (Module) |
nur für Module zulässig |
Parameter |
nur für Parameter zulässig |
Eigenschaft (Property) |
bezieht auf get/set-Eigenschaften |
Rückgabewert (Return Value) |
bezieht sich auf den Rückgabewert |
Struktur (struct) |
nur für Struktur zulässig |