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
- Reflection ist leistungsfähig, aber langsam — bis zu 10–100 × teurer als ein direkter Methodenaufruf.
- In leistungskritischen Szenarien sollten Sie zuvor entdeckte
MethodInfo-Objekte zwischenspeichern (Caching). - Reflection kann auf private Mitglieder zugreifen, daher sind Sicherheitsbeschränkungen wichtig.
dynamic- oderExpression<T>-basierte Alternativen können in manchen Fällen effizienter sein.
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,PropertyInfousw.). - 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
BindingFlagserreicht werden. - Hohe Leistungskosten — sollte nur bei Bedarf verwendet werden.
- Wird häufig in Plugins, Serializern, ORMs und Testframeworks eingesetzt.
Ähnliche Artikel
Codeanalyse mit der Roslyn Compiler API in C#
Lernen Sie Codeanalyse in C# mit der Roslyn Compiler API, einschließlich Syntaxbäumen und Codegenerierung.
Das Konzept von Source Generators in C# (C# 9+)
Lernen Sie Source Generators in C#, um Code zur Compile-Zeit zu erzeugen und Performance zu verbessern.
Designmuster in C# (Factory, Singleton, Repository, Observer)
Lernen Sie Designmuster in C#, wie Factory, Singleton und Repository, für flexible und wartbare Anwendungen.
Interfaces und Abstrakte Klassen in C#
Lernen Sie Interfaces und abstrakte Klassen in C#, ihre Unterschiede und den Einsatz für sauberes, erweiterbares Design.
Klassen, Objekte, Eigenschaften und Methoden in C#
Erlernen Sie die Grundlagen von Klassen, Objekten, Eigenschaften und Methoden in C# für objektorientierte Programmierung.
SOLID-Prinzipien mit C#
SOLID-Prinzipien mit C#-Beispielen: flexiblen, wartbaren und testbaren Code erstellen.