Wird geladen...

Reflection und Late Binding in C#

Lernen Sie Reflection und Late Binding in C#, um Typen zur Laufzeit zu analysieren und dynamische Systeme zu erstellen.

In C# ermöglicht Reflection den Zugriff auf Typinformationen zur Laufzeit (runtime), die Arbeit mit Typen und das dynamische Erstellen von Objekten. Late Binding (späte Bindung) bedeutet, auf Objekte zuzugreifen, deren Typen zur Kompilierzeit unbekannt sind. Mit diesen beiden Mechanismen lassen sich flexible, pluginbasierte oder dynamisch modulare Systeme entwickeln.


Was ist Reflection?

Reflection ist ein leistungsfähiger Mechanismus, der es ermöglicht, Typen (Klassen, Methoden, Eigenschaften, Felder usw.) in einer Assembly zur Laufzeit zu untersuchen und zu verwenden. Beispielsweise können Sie Klassen, Methoden, Attribute oder deren Werte innerhalb einer Assembly-Datei anzeigen.


using System;
using System.Reflection;

class Beispiel
{
    public int Zahl { get; set; }
    public void Schreiben() => Console.WriteLine("Schreiben() Methode aufgerufen.");
}

class Program
{
    static void Main()
    {
        Type typ = typeof(Beispiel);
        Console.WriteLine($"Klassenname: {typ.Name}");

        // Eigenschaften auflisten
        foreach (var prop in typ.GetProperties())
            Console.WriteLine($"Eigenschaft: {prop.Name}");

        // Methoden auflisten
        foreach (var methode in typ.GetMethods())
            Console.WriteLine($"Methode: {methode.Name}");
    }
}

In diesem Beispiel bietet das Type-Objekt Zugriff auf alle Informationen über die Klassenstruktur. Mit Methoden wie GetMethods(), GetProperties() und GetFields() können detaillierte Untersuchungen durchgeführt werden.


Was ist Late Binding?

Late Binding bedeutet, zur Laufzeit eine Instanz einer Klasse zu erstellen, deren Typ zur Kompilierzeit unbekannt ist. Mit Reflection kann die Klasse geladen, das Objekt erstellt und Methoden dynamisch aufgerufen werden. Sie wird häufig in Plugin-Systemen, beim Laden externer DLLs und bei der dynamischen Typverwaltung verwendet.


using System;
using System.Reflection;

class Begruesser
{
    public void Begruessen(string name)
    {
        Console.WriteLine($"Hallo, {name}!");
    }
}

class Program
{
    static void Main()
    {
        // Objekt zur Laufzeit anhand des Typs erstellen
        Type typ = Type.GetType("Begruesser");
        object instanz = Activator.CreateInstance(typ);

        // Methode aufrufen (Late Binding)
        MethodInfo methode = typ.GetMethod("Begruessen");
        methode.Invoke(instanz, new object[] { "Ahmet" });
    }
}

Hier wird die Klasse Begruesser zur Laufzeit anhand ihres Namens geladen. Da der Typ zur Kompilierzeit unbekannt war, nennt man dies späte Bindung.


Dynamisches Laden über Assembly

Mit den Methoden Assembly.LoadFrom() oder Assembly.Load() können externe DLLs geladen und deren Typen entdeckt werden. Dieser Ansatz wird häufig in Plugin- oder modularen Architekturen verwendet.


using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        // Externe DLL laden
        Assembly dll = Assembly.LoadFrom("MeineBibliothek.dll");

        // Typen auflisten
        foreach (var typ in dll.GetTypes())
            Console.WriteLine($"Typ: {typ.FullName}");

        // Instanz erstellen und Methode aufrufen
        Type zielTyp = dll.GetType("MeineBibliothek.MathHelper");
        object instanz = Activator.CreateInstance(zielTyp);
        MethodInfo methode = zielTyp.GetMethod("Addieren");

        object ergebnis = methode.Invoke(instanz, new object[] { 3, 5 });
        Console.WriteLine($"Ergebnis der Addition: {ergebnis}");
    }
}

Mit dieser Methode können externe Bibliotheken während der Laufzeit geladen und deren Typen und Methoden dynamisch verwendet werden.


Dynamischer Zugriff auf Eigenschaften und Felder

Reflection ist nicht auf Methodenaufrufe beschränkt; Sie können auch auf Eigenschaften- und Feldwerte zugreifen und sie sogar ändern.


using System;
using System.Reflection;

class Auto
{
    public string Marke { get; set; } = "Ford";
    private int Geschwindigkeit = 120;
}

class Program
{
    static void Main()
    {
        var auto = new Auto();
        Type typ = auto.GetType();

        // Öffentliche Eigenschaft lesen
        var prop = typ.GetProperty("Marke");
        Console.WriteLine("Marke: " + prop.GetValue(auto));

        // Auf privates Feld zugreifen
        var feld = typ.GetField("Geschwindigkeit", BindingFlags.NonPublic | BindingFlags.Instance);
        Console.WriteLine("Geschwindigkeit: " + feld.GetValue(auto));

        // Wert ändern
        feld.SetValue(auto, 200);
        Console.WriteLine("Neue Geschwindigkeit: " + feld.GetValue(auto));
    }
}

Mit BindingFlags können Sie steuern, ob auf öffentliche, private oder statische Mitglieder zugegriffen werden soll.


Zugriff auf Attributinformationen

Mit Reflection können auch Attribute-Informationen, die auf Klassen oder Mitgliedern definiert sind, abgerufen werden. Diese Funktion wird häufig in metadatenbasierten Bibliotheken (z. B. ORM, Serializer) verwendet.


using System;

[AttributeUsage(AttributeTargets.Class)]
class InfoAttribut : Attribute
{
    public string Beschreibung { get; }
    public InfoAttribut(string beschreibung) => Beschreibung = beschreibung;
}

[InfoAttribut("Diese Klasse dient als Beispiel.")]
class Beispiel { }

class Program
{
    static void Main()
    {
        Type typ = typeof(Beispiel);
        var attr = (InfoAttribut)Attribute.GetCustomAttribute(typ, typeof(InfoAttribut));

        Console.WriteLine($"Beschreibung: {attr.Beschreibung}");
    }
}

Mit diesem Mechanismus können Klassen mit Metadaten versehen werden, die dann zur Laufzeit ausgelesen werden können.


Leistungs- und Sicherheitsüberlegungen


Beispiel: Plugin-System

Reflection wird häufig verwendet, um Plugin- oder modulare Systeme zu entwickeln. Im folgenden Beispiel werden Klassen in einer DLL gesucht, die das IPlugin-Interface implementieren, und dann dynamisch geladen.


using System;
using System.Linq;
using System.Reflection;

public interface IPlugin
{
    string Name { get; }
    void Ausführen();
}

class Program
{
    static void Main()
    {
        Assembly dll = Assembly.LoadFrom("PluginPaket.dll");
        var pluginTypen = dll.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);

        foreach (var typ in pluginTypen)
        {
            IPlugin plugin = (IPlugin)Activator.CreateInstance(typ);
            Console.WriteLine($"Plugin: {plugin.Name}");
            plugin.Ausführen();
        }
    }
}

Mit diesem Aufbau können neue Plugins zur Laufzeit ins System integriert werden, auch wenn sie zur Kompilierzeit noch unbekannt waren.


TL;DR

  • Reflection: Ermöglicht den Zugriff auf Typinformationen und dynamische Nutzung zur Laufzeit (Type, MethodInfo, PropertyInfo usw.).
  • Late Binding: Lädt und verwendet Klassen zur Laufzeit, die zur Kompilierzeit unbekannt sind.
  • Externe DLLs können mit Assembly.LoadFrom() dynamisch geladen und verwendet werden.
  • Private Mitglieder können mit BindingFlags erreicht werden.
  • Hohe Leistungskosten — sollte nur bei Bedarf verwendet werden.
  • Wird häufig in Plugins, Serializern, ORMs und Testframeworks eingesetzt.

Ähnliche Artikel