Verwenden von Attributen in C#Using Attributes in C#

Attribute bieten die Möglichkeit, Informationen in deklarativer Form mit Code zu verknüpfen.Attributes provide a way of associating information with code in a declarative way. Attribute können außerdem als wiederverwendbare Elemente genutzt werden, die auf eine Vielzahl von Zielen angewendet werden können.They can also provide a reusable element that can be applied to a variety of targets.

Betrachten wir z.B. das [Obsolete]-Attribut.Consider the [Obsolete] attribute. Es kann auf Klassen, Strukturen, Methoden, Konstruktoren und mehr angewendet werden.It can be applied to classes, structs, methods, constructors, and more. Mit ihm wird das Element als veraltet deklariert.It declares that the element is obsolete. Anschließend ist es die Aufgabe des C#-Compilers, nach diesem Attribut zu suchen und Aktionen auszuführen.It's then up to the C# compiler to look for this attribute, and do some action in response.

In diesem Tutorial erfahren Sie, wie Sie Attribute zu Ihrem Code hinzufügen sowie eigene Attribute erstellen und verwenden, und Sie lernen einige der Attribute kennen, die in .NET Core integriert sind.In this tutorial, you'll be introduced to how to add attributes to your code, how to create and use your own attributes, and how to use some attributes that are built into .NET Core.

Erforderliche KomponentenPrerequisites

Sie müssen Ihren Computer zur Ausführung von .NET Core einrichten.You’ll need to setup your machine to run .NET core. Die Installationsanweisungen finden Sie auf der Seite .NET Core.You can find the installation instructions on the .NET Core page. Sie können diese Anwendung unter Windows, Ubuntu Linux, macOS oder in einem Docker-Container ausführen.You can run this application on Windows, Ubuntu Linux, macOS or in a Docker container. Sie müssen Ihren bevorzugten Code-Editor installieren.You’ll need to install your favorite code editor. In den folgenden Beschreibungen wird Visual Studio Code verwendet. Hierbei handelt es sich um einen plattformübergreifenden Open Source-Editor.The descriptions below use Visual Studio Code which is an open source, cross platform editor. Sie können jedoch auch ein beliebiges anderes Tool verwenden, mit dem Sie vertraut sind.However, you can use whatever tools you are comfortable with.

Erstellen der AnwendungCreate the Application

Nachdem Sie alle Tools installiert haben, erstellen Sie eine neue .NET Core-Anwendung.Now that you've installed all the tools, create a new .NET Core application. Um den Befehlszeilengenerator zu verwenden, führen Sie den folgenden Befehl in Ihrer bevorzugten Shell aus:To use the command line generator, execute the following command in your favorite shell:

dotnet new console

Mit diesem Befehl werden .NET Core-Basisprojektdateien erstellt.This command will create barebones .NET core project files. Sie müssen dotnet restore ausführen, um die abhängigen Komponenten wiederherzustellen, die zum Kompilieren dieses Projekts erforderlich sind.You will need to execute dotnet restore to restore the dependencies needed to compile this project.

Hinweis

Starting with .NET Core 2.0, you don't have to run dotnet restore because it's run implicitly by all commands, such as dotnet build and dotnet run, that require a restore to occur. It's still a valid command in certain scenarios where doing an explicit restore makes sense, such as continuous integration builds in Visual Studio Team Services or in build systems that need to explicitly control the time at which the restore occurs.

Verwenden Sie zum Ausführen des Programms dotnet run.To execute the program, use dotnet run. Es sollte „Hello, World“ auf der Konsole ausgegeben werden.You should see "Hello, World" output to the console.

Hinzufügen von Attributen zum CodeHow to add attributes to code

In C# sind Attribute Klassen, die von der Attribute-Basisklasse erben.In C#, attributes are classes that inherit from the Attribute base class. Alle Klassen, die von Attribute erben, können als eine Art von „Tag“ für andere Codeelemente verwendet werden.Any class that inherits from Attribute can be used as a sort of "tag" on other pieces of code. Beispielsweise gibt es das Attribut ObsoleteAttribute.For instance, there is an attribute called ObsoleteAttribute. Mit diesem Attribut wird gekennzeichnet, dass der Code veraltet ist und nicht mehr verwendet werden sollte.This is used to signal that code is obsolete and shouldn't be used anymore. Sie können eine Klasse beispielsweise mit diesem Attribut markieren, indem Sie eckige Klammern verwenden.You can place this attribute on a class, for instance, by using square brackets.

[Obsolete]
public class MyClass
{

}

Obwohl der Name der Klasse ObsoleteAttribute lautet, kann im Code nur [Obsolete] verwendet werden.Note that while the class is called ObsoleteAttribute, it's only necessary to use [Obsolete] in the code. Dies ist eine Konvention von C#.This is a convention that C# follows. Wenn Sie möchten, können Sie auch den vollständigen Namen, [ObsoleteAttribute], verwenden.You can use the full name [ObsoleteAttribute] if you choose.

Wenn Sie eine Klasse als veraltet markieren, sollten Sie Informationen dazu geben, warum die Klasse veraltet ist und/oder was stattdessen verwendet werden sollte.When marking a class obsolete, it's a good idea to provide some information as to why it's obsolete, and/or what to use instead. Um dies zu tun, übergeben Sie einen Zeichenfolgenparameter an das Obsolete-Attribut.Do this by passing a string parameter to the Obsolete attribute.

[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{

}

Die Zeichenfolge wird als Argument an einen ObsoleteAttribute-Konstruktor übergeben, so als ob Sie var attr = new ObsoleteAttribute("some string") schreiben würden.The string is being passed as an argument to an ObsoleteAttribute constructor, just as if you were writing var attr = new ObsoleteAttribute("some string").

Die Parameter für einen Attributkonstruktor sind auf einfache Typen/Literale beschränkt: bool, int, double, string, Type, enums, etc und Arrays dieser Typen.Parameters to an attribute constructor are limited to simple types/literals: bool, int, double, string, Type, enums, etc and arrays of those types. Sie können keine Ausdrücke oder Variablen verwenden.You can not use an expression or a variable. Es ist möglich, Positionsparameter oder benannte Parameter einzusetzen.You are free to use positional or named parameters.

Erstellen eigener AttributeHow to create your own attribute

Das Erstellen eines Attributs ist so einfach wie das Erben von der Attribute-Basisklasse.Creating an attribute is as simple as inheriting from the Attribute base class.

public class MySpecialAttribute : Attribute
{

}

Durch den Code oben kann jetzt [MySpecial] (oder [MySpecialAttribute]) als Attribut an anderer Stelle in der Codebasis verwendet werden.With the above, I can now use [MySpecial] (or [MySpecialAttribute]) as an attribute elsewhere in the code base.

[MySpecial]
public class SomeOtherClass
{

}

Attribute in der .NET-Basisklassenbibliothek, z.B. ObsoleteAttribute, lösen ein bestimmtes Verhalten im Compiler aus.Attributes in the .NET base class library like ObsoleteAttribute trigger certain behaviors within the compiler. Die erstellten Attribute dienen jedoch nur als Metadaten, sie führen nicht zu Code innerhalb der Attributklasse, der ausgeführt wird.However, any attribute you create acts only as metadata, and doesn't result in any code within the attribute class being executed. Es liegt an Ihnen, diese Metadaten an anderer Stelle im Code einzusetzen (hierzu später mehr in diesem Tutorial).It's up to you to act on that metadata elsewhere in your code (more on that later in the tutorial).

Es gibt hierbei ein Problem, das beachtet werden muss.There is a 'gotcha' here to watch out for. Wie oben erwähnt, können bei der Verwendung von Attributen nur bestimmte Typen als Argumente übergeben werden.As mentioned above, only certain types are allowed to be passed as arguments when using attributes. Wenn Sie aber einen Attributtyp erstellen, hindert der C#-Compiler Sie nicht daran, diese Parameter zu erstellen.However, when creating an attribute type, the C# compiler won't stop you from creating those parameters. Im nachstehenden Beispiel habe ich ein Attribut mit einem Konstruktor erstellt, der problemlos kompiliert werden kann.In the below example, I've created an attribute with a constructor that compiles just fine.

public class GotchaAttribute : Attribute
{
    public GotchaAttribute(Foo myClass, string str) {
        
    }
}

Dieser Konstruktor kann aber nicht mit der Attributsyntax verwendet werden.However, you will be unable to use this constructor with attribute syntax.

[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{

}

Der obige Code führt zu einem Compilerfehler wie diesem: Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter typeThe above will cause a compiler error like Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type

Einschränken der AttributverwendungHow to restrict attribute usage

Attribute können für verschiedene Ziele verwendet werden.Attributes can be used on a number of "targets". In den obigen Beispielen wurde die Verwendung für Klassen gezeigt, aber Attribute können auch für folgende Elemente verwendet werden:The above examples show them on classes, but they can also be used on:

  • AssemblyAssembly
  • KlasseClass
  • KonstruktorConstructor
  • DelegateDelegate
  • EnumEnum
  • EreignisEvent
  • FeldField
  • GenericParameterGenericParameter
  • SchnittstelleInterface
  • MethodeMethod
  • ModulModule
  • ParameterParameter
  • EigenschaftProperty
  • ReturnValueReturnValue
  • StrukturStruct

Wenn Sie eine Attributklasse erstellen, lässt C# standardmäßig die Verwendung dieses Attributs für alle möglichen Attributziele zu.When you create an attribute class, by default, C# will allow you to use that attribute on any of the possible attribute targets. Wenn Sie Ihr Attribut auf bestimmte Ziele beschränken möchten, erreichen Sie dies durch Verwendung von AttributeUsageAttribute für Ihre Attributklasse.If you want to restrict your attribute to certain targets, you can do so by using the AttributeUsageAttribute on your attribute class. Ganz richtig, ein Attribut für ein Attribut!That's right, an attribute on an attribute!

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{

}

Wenn Sie versuchen, das oben gezeigte Attribut für ein Element zu verwenden, bei dem es sich nicht um eine Klasse oder eine Struktur handelt, erhalten Sie einen Compilerfehler wie diesen: Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarationsIf you attempt to put the above attribute on something that's not a class or a struct, you will get a compiler error like Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarations

public class Foo
{
    // if the below attribute was uncommented, it would cause a compiler error
    // [MyAttributeForClassAndStructOnly]
    public Foo() {

    }
}

Verwenden von Attributen, die an Codeelemente angefügt sindHow to use attributes attached to a code element

Attribute fungieren als Metadaten.Attributes act as metadata. Ohne Aktivität von außen bewirken sie zunächst nichts.Without some outward force, they won't actually do anything.

Um nach Attributen zu suchen und Aktionen auszuführen, ist im Allgemeinen eine Reflektion erforderlich.To find and act on attributes, Reflection is generally needed. In diesem Tutorial wird nicht ausführlich auf die Reflektion eingegangen. Die Grundidee hierbei ist jedoch folgende: Mithilfe der Reflektion ist es möglich, Code in C# zu schreiben, mit dem anderer Code untersucht wird.I won't cover Reflection in-depth in this tutorial, but the basic idea is that Reflection allows you to write code in C# that examines other code.

Sie können beispielsweise mithilfe der Reflektion Informationen zu einer Klasse abrufen:For instance, you can use Reflection to get information about a class:

TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);

Es wird eine Ausgabe ähnlich der folgenden erzeugt: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nullThat will print out something like: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Sobald Sie über ein TypeInfo-Objekt (oder MemberInfo, FieldInfo usw.) verfügen, können Sie die GetCustomAttributes-Methode verwenden.Once you have a TypeInfo object (or a MemberInfo, FieldInfo, etc), you can use the GetCustomAttributes method. Dadurch wird eine Auflistung von Attribute-Objekte zurückgegeben.This will return a collection of Attribute objects. Sie können auch GetCustomAttribute verwenden und einen Attributtyp angeben.You can also use GetCustomAttribute and specify an Attribute type.

Hier ein Beispiel zur Verwendung von GetCustomAttributes für eine MemberInfo-Instanz für MyClass (die, wie zuvor gezeigt, über ein [Obsolete]-Attribut verfügt).Here's an example of using GetCustomAttributes on a MemberInfo instance for MyClass (which we saw earlier has an [Obsolete] attribute on it).

var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
    Console.WriteLine("Attribute on MyClass: " + attr.GetType().Name);

Dies führt zur folgenden Konsolenausgabe: Attribute on MyClass: ObsoleteAttribute.That will print to console: Attribute on MyClass: ObsoleteAttribute. Versuchen Sie, weitere Attribute zu MyClass hinzuzufügen.Try adding other attributes to MyClass.

Es ist wichtig, darauf hinzuweisen, dass diese Attribute-Objekte verzögert instanziiert werden.It's important to note that these Attribute objects are instantiated lazily. Anders ausgedrückt: Sie werden erst instanziiert, wenn Sie GetCustomAttribute oder GetCustomAttributes verwenden.That is, they won't be instantiated until you use GetCustomAttribute or GetCustomAttributes. Sie werden außerdem jedes Mal instanziiert.They are also instantiated each time. Das zweimalige Aufrufen von GetCustomAttributes in einer Zeile führt zur Rückgabe von zwei unterschiedlichen Instanzen von ObsoleteAttribute.Calling GetCustomAttributes twice in a row will return two different instances of ObsoleteAttribute.

Allgemeine Attribute in der BasisklassenbibliothekCommon attributes in the base class library (BCL)

Attribute werden in vielen Tools und Frameworks verwendet.Attributes are used by many tools and frameworks. NUnit verwendet Attribute wie z.B. [Test] und [TestFixture], die vom NUnit Test Runner verwendet werden.NUnit uses attributes like [Test] and [TestFixture] that are used by the NUnit test runner. ASP.NET MVC verwendet Attribute wie [Authorize] und stellt ein Aktionsfilterframework bereit, um übergreifende Anforderungen (Cross-Cutting Concerns) für MVC-Aktionen umzusetzen.ASP.NET MVC uses attributes like [Authorize] and provides an action filter framework to perform cross-cutting concerns on MVC actions. PostSharp verwendet die Attributsyntax, um eine aspektorientierte Programmierung in C# zu ermöglichen.PostSharp uses the attribute syntax to allow aspect-oriented programming in C#.

Nachfolgend werden einige wichtige Attribute aufgeführt, die in die .NET Core-Basisklassenbibliotheken integriert sind:Here are a few notable attributes built into the .NET Core base class libraries:

  • [Obsolete].[Obsolete]. Dieses Attribut wurde in den obigen Beispielen verwendet, es ist im System-Namespace enthalten.This one was used in the above examples, and it lives in the System namespace. Es ist nützlich, um eine deklarative Dokumentation für eine sich ändernde Codebasis bereitzustellen.It is useful to provide declarative documentation about a changing code base. Eine Meldung kann in Form einer Zeichenfolge bereitgestellt werden, und ein weiterer, boolescher Parameter kann für eine Eskalation von einer Compilerwarnung zu einem Compilerfehler verwendet werden.A message can be provided in the form of a string, and another boolean parameter can be used to escalate from a compiler warning to a compiler error.

  • [Conditional].[Conditional]. Dieses Attribut ist im System.Diagnostics-Namespace enthalten.This attribute is in the System.Diagnostics namespace. Es kann auf Methoden (oder Attributklassen) angewendet werden.This attribute can be applied to methods (or attribute classes). Sie müssen eine Zeichenfolge an den Konstruktor übergeben.You must pass a string to the constructor. Wenn diese Zeichenfolge einer #define-Direktive entspricht, werden alle Aufrufe an diese Methode (aber nicht die Methode selbst) durch den C#-Compiler entfernt.If that string matches a #define directive, then any calls to that method (but not the method itself) will be removed by the C# compiler. Dieses Attribut wird typischerweise zum Debuggen (zu Diagnosezwecken) eingesetzt.Typically this is used for debugging (diagnostics) purposes.

  • [CallerMemberName].[CallerMemberName]. Dieses Attribut kann für Parameter verwendet werden und ist im System.Runtime.CompilerServices-Namespace enthalten.This attribute can be used on parameters, and lives in the System.Runtime.CompilerServices namespace. Es handelt sich um ein Attribut, mit dem der Name der Methode eingeführt wird, die eine andere Methode aufruft.This is an attribute that is used to inject the name of the method that is calling another method. So werden typischerweise „magische Zeichenfolgen“ beim Implementieren von „INotifyPropertyChanged“ in verschiedenen UI-Frameworks beseitigt.This is typically used as a way to eliminate 'magic strings' when implementing INotifyPropertyChanged in various UI frameworks. Ein Beispiel:As an example:

public class MyUIClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void ExecutePropertyChanged([CallerMemberName] string propertyName = null)
    {
        if(PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _name;
    public string Name {
        get { return _name;}
        set {
            if(value != _name) {
                _name = value;
                ExecutePropertyChanged();   // notice that "Name" is not needed here explicitly
            }
        }
    }
}

Im Code oben ist keine literale "Name"-Zeichenfolge erforderlich.In the above code, you don't have to have a literal "Name" string. Dies kann dazu beitragen, Programmfehler aufgrund von Rechtschreibfehlern zu vermeiden, und es erleichtert das Refactoring/Umbenennen.This can help prevent typo-related bugs and also makes for smoother refactoring/renaming.

ZusammenfassungSummary

Attribute ermöglichen eine deklarative Programmierung in C#.Attributes bring declarative power to C#. Es handelt sich jedoch um eine Form von Metadaten, die Attribute können nicht selbst agieren.But they are a form of code as meta-data, and don't act by themselves.