Menu
Coddy logo textTech

Attribute und Reflection

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 44 von 70.

Attribute sind Metadaten-Tags, die Sie an Code-Elemente wie Klassen, Methoden oder Eigenschaften anhängen. Sie ändern nicht direkt, wie der Code ausgeführt wird, aber sie stellen Informationen bereit, die zur Laufzeit gelesen werden können. Reflection ist der Mechanismus, der diese Metadaten liest.

Sie wenden ein Attribut an, indem Sie es in eckigen Klammern über dem Zielelement platzieren:

[Obsolete("Use NewMethod instead")]
public void OldMethod() { }

[Serializable]
public class Person
{
    public string Name { get; set; }
}

Sie können benutzerdefinierte Attribute erstellen, indem Sie von Attribute erben:

public class AuthorAttribute : Attribute
{
    public string Name { get; }
    public AuthorAttribute(string name) => Name = name;
}

[Author("John")]
public class Calculator { }

Reflection ermöglicht es Ihnen, Typen zu untersuchen und Attribute zur Laufzeit unter Verwendung des Namespaces System.Reflection auszulesen:

Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name);  // John

Sie können auch Methoden und Eigenschaften entdecken und diese dynamisch aufrufen:

MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
    Console.WriteLine(method.Name);

Attribute und Reflection bilden die Grundlage vieler Frameworks – Serialisierungsbibliotheken verwenden sie, um die JSON-Ausgabe zu steuern, Test-Frameworks nutzen sie, um Testmethoden zu entdecken, und Dependency-Injection-Container verwenden sie, um Dienste automatisch zu verknüpfen.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Plugin-Erkennungssystem erstellen, das benutzerdefinierte Attribute und Reflection verwendet, um Klassen, die als Plugins markiert sind, automatisch zu finden und zu beschreiben. Dies ähnelt der Art und Weise, wie echte Frameworks Komponenten, Testmethoden oder API-Endpunkte zur Laufzeit entdecken.

Sie werden Ihren Code über drei Dateien organisieren:

  • PluginAttribute.cs: Erstellen Sie ein benutzerdefiniertes Attribut namens PluginAttribute im Namespace PluginSystem. Ihr Attribut sollte:
    • Von Attribute erben
    • Zwei schreibgeschützte Eigenschaften haben: Name (string) und Version (string)
    • Beide Werte über seinen Konstruktor akzeptieren
  • Plugins.cs: Erstellen Sie mehrere Plugin-Klassen im Namespace PluginSystem. Einige sollten mit Ihrem PluginAttribute dekoriert sein, und eine nicht:
    • ImageProcessor - markiert mit [Plugin("Image Processor", "1.0")]
    • DataExporter - markiert mit [Plugin("Data Exporter", "2.5")]
    • HelperUtility - NICHT mit einem Attribut markiert (dies ist nur eine reguläre Klasse)
    Jede Klasse kann leer sein – wir sind nur daran interessiert, ihre Metadaten durch Reflection zu entdecken.
  • Program.cs: Verwenden Sie in Ihrer Hauptdatei Reflection, um alle Klassen zu entdecken, die das PluginAttribute besitzen. Geben Sie für jedes entdeckte Plugin seine Informationen aus. Sie müssen:
    • Alle Typen aus dem aktuellen Assembly abrufen
    • Jeden Typ auf das PluginAttribute prüfen
    • Die Eigenschaften Name und Version des Attributs extrahieren und anzeigen

Verwenden Sie System.Reflection, um Typen zu untersuchen und benutzerdefinierte Attribute abzurufen. Die Methode GetCustomAttribute<T>() gibt null zurück, wenn das Attribut nicht vorhanden ist, sodass Sie dies verwenden können, um zu filtern, welche Klassen tatsächliche Plugins sind.

Geben Sie jedes entdeckte Plugin in diesem Format aus, eine pro Zeile:

Plugin: {Name} (v{Version})

Die Plugins sollten in der Reihenfolge ausgegeben werden: ImageProcessor zuerst, dann DataExporter. Die Klasse HelperUtility sollte nicht in der Ausgabe erscheinen, da ihr das Attribut fehlt.

Erwartete Ausgabe:

Plugin: Image Processor (v1.0)
Plugin: Data Exporter (v2.5)

Diese Herausforderung zeigt, wie Frameworks Attribute als Markierungen und Reflection verwenden, um sie zu entdecken – dieselbe Technik treibt Dependency-Injection-Container, Serialisierungsbibliotheken und Test-Frameworks an!

Spickzettel

Attribute sind Metadaten-Tags, die in eckigen Klammern über Code-Elementen platziert werden. Sie liefern Informationen, die zur Laufzeit ausgelesen werden können:

[Obsolete("Use NewMethod instead")]
public void OldMethod() { }

[Serializable]
public class Person
{
    public string Name { get; set; }
}

Erstellen Sie benutzerdefinierte Attribute, indem Sie von Attribute erben:

public class AuthorAttribute : Attribute
{
    public string Name { get; }
    public AuthorAttribute(string name) => Name = name;
}

[Author("John")]
public class Calculator { }

Reflection ermöglicht es Ihnen, Typen zu untersuchen und Attribute zur Laufzeit mithilfe des Namespaces System.Reflection auszulesen:

Type type = typeof(Calculator);
var attr = type.GetCustomAttribute<AuthorAttribute>();
Console.WriteLine(attr.Name);  // John

Methoden und Eigenschaften dynamisch entdecken:

MethodInfo[] methods = type.GetMethods();
foreach (var method in methods)
    Console.WriteLine(method.Name);

Die Methode GetCustomAttribute<T>() gibt null zurück, wenn das Attribut nicht vorhanden ist, was es Ihnen ermöglicht, Typen basierend auf dem Vorhandensein von Attributen zu filtern.

Probier es selbst

using System;
using System.Reflection;
using PluginSystem;

class Program
{
    public static void Main(string[] args)
    {
        // TODO: Alle Typen aus dem aktuellen Assembly abrufen
        // Hint: Verwende Assembly.GetExecutingAssembly().GetTypes()
        
        // TODO: Alle Typen durchlaufen und prüfen, ob sie das PluginAttribute besitzen
        // Hint: Verwende type.GetCustomAttribute<PluginAttribute>()
        
        // TODO: Wenn das Attribut existiert, die Plugin-Informationen in folgendem Format ausgeben:
        // Plugin: {Name} (v{Version})
        
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung