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 du an Codeelemente wie Klassen, methods oder Eigenschaften anhängst. Sie ändern nicht direkt, wie der Code ausgeführt wird, sondern stellen Informationen bereit, die zur Laufzeit gelesen werden können. Reflexion ist der Mechanismus, der diese Metadaten liest.

Du wendest ein Attribut an, indem du es in eckigen Klammern über dem Zielelement platzierst:

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

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

Du kannst benutzerdefinierte Attribute erstellen, indem du von Attribute erbst:

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

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

Mit Reflection kannst du Typen untersuchen und zur Laufzeit mithilfe des Namespace System.Reflection Attribute auslesen:

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

Du kannst auch methods und Eigenschaften entdecken und sie 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 erkennen, und Dependency-Injection-Container setzen sie ein, um Dienste automatisch zu verbinden.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Plugin-Erkennungssystem, das benutzerdefinierte Attribute und Reflection verwendet, um Klassen, die als Plugins gekennzeichnet sind, automatisch zu finden und zu beschreiben. Dies ähnelt der Funktionsweise echter Frameworks, die Komponenten, Testmethoden oder API-Endpunkte zur Laufzeit erkennen.

Du organisierst deinen Code auf drei Dateien verteilt:

  • PluginAttribute.cs: Erstelle ein benutzerdefiniertes Attribut namens PluginAttribute im Namespace PluginSystem. Dein Attribut sollte:
    • Von Attribute erben
    • Zwei schreibgeschützte Eigenschaften besitzen: Name (string) und Version (string)
    • Beide Werte über seinen Konstruktor akzeptieren
  • Plugins.cs: Erstelle mehrere Plugin-Klassen im Namespace PluginSystem. Einige sollten mit deinem PluginAttribute dekoriert sein, eine jedoch nicht:
    • ImageProcessor – gekennzeichnet mit [Plugin("Image Processor", "1.0")]
    • DataExporter – gekennzeichnet mit [Plugin("Data Exporter", "2.5")]
    • HelperUtility – NICHT mit einem Attribut gekennzeichnet (dies ist einfach eine reguläre Klasse)
    Jede Klasse kann leer sein – wir interessieren uns ausschließlich dafür, ihre Metadaten über Reflection zu ermitteln.
  • Program.cs: Verwende in deiner Hauptdatei Reflection, um alle Klassen zu erkennen, die über das PluginAttribute verfügen. Gib für jedes erkannte Plugin seine Informationen aus. Dazu musst du:
    • Alle Typen aus der aktuellen Assembly abrufen
    • Jeden Typ auf das PluginAttribute überprüfen
    • Die Eigenschaften Name und Version des Attributs auslesen und anzeigen

Verwende System.Reflection, um Typen zu untersuchen und benutzerdefinierte Attribute abzurufen. Die Methode GetCustomAttribute<T>() gibt null zurück, wenn das Attribut nicht vorhanden ist. Du kannst dies daher verwenden, um zu filtern, welche Klassen tatsächlich Plugins sind.

Gib jedes erkannte Plugin in diesem Format aus, eines pro Zeile:

Plugin: {Name} (v{Version})

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

Erwartete Ausgabe:

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

Diese Aufgabe veranschaulicht, wie Frameworks Attribute als Markierungen und Reflection verwenden, um sie zu erkennen – dieselbe Technik bildet die Grundlage für Dependency-Injection-Container, Serialisierungsbibliotheken und Test-Frameworks!

Probier es selbst

using System;
using System.Reflection;
using PluginSystem;

class Program
{
    public static void Main(string[] args)
    {
        // TODO: Hole alle Typen aus der aktuellen Assembly
        // Hinweis: Verwende Assembly.GetExecutingAssembly().GetTypes()
        
        // TODO: Gehe durch jeden Typ und prüfe, ob er das PluginAttribute hat
        // Hinweis: Verwende type.GetCustomAttribute<PluginAttribute>()
        
        // TODO: Wenn das Attribut existiert, gib die Plugin-Info im Format aus:
        // 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

Übe selbstständig: Online-C#-Compiler