C# Reflection: Laufzeit-Typinformation & dynamische Programmierung
Was ist Reflection?
Reflection (Namespace System.Reflection) ermöglicht es, zur Laufzeit Metadaten von Typen (Klassen, Structs, Interfaces, Enums, Methoden, Properties, Attribute, …) zu untersuchen, Instanzen zu erzeugen und Member aufzurufen – ohne die Typen zur Kompilierzeit zu kennen.
Hauptanwendungen
- Attribute zur Laufzeit auslesen.
- Typen in Assemblys entdecken & instanziieren (Plugin-Architekturen).
- Late Binding: Methoden/Properties per Name aufrufen.
- Typen zur Laufzeit erzeugen (
System.Reflection.Emit,AssemblyBuilder). - Serialisierung, Dependency Injection, ORM, Testing-Frameworks.
Wichtige Klassen
| Klasse | Zweck |
|---|---|
Type | Zentrale Darstellung eines Typs (erhalten via typeof(T) oder obj.GetType()). |
Assembly | Geladene Assembly; Zugriff auf exportierte Typen. |
MemberInfo (Basisklasse) | Basisklasse für MethodInfo, PropertyInfo, FieldInfo, ConstructorInfo, EventInfo. |
MethodInfo | Methoden-Metadaten; Invoke(obj, args) für Aufruf. |
PropertyInfo | Property-Metadaten; GetValue/SetValue. |
CustomAttributeData | Attribute-Daten ohne Instanzierung des Attribut-Objekts (nur Metadaten). |
Attribute auslesen (Beispiel aus vorigem Kapitel)
using System;
using System.Reflection;
[DebugInfo(45, "Zara", "2023-01-01", Message = "Mismatch")]
public class Rectangle { public double Area => 10; }
public class Program
{
static void Main()
{
Type t = typeof(Rectangle);
// Klassen-Attribute
foreach (var attr in t.GetCustomAttributes())
Console.WriteLine($"Class Bug: {attr.BugNumber} - {attr.Message}");
// Methoden-Attribute
foreach (var method in t.GetMethods())
{
foreach (var attr in method.GetCustomAttributes())
Console.WriteLine($"Method {method.Name}: Bug {attr.BugNumber}");
}
}
}
Late Binding – Methode per Name aufrufen
object obj = "Hello World";
Type t = obj.GetType();
MethodInfo mi = t.GetMethod("Substring", new[] { typeof(int) });
string result = (string)mi.Invoke(obj, new object[] { 6 }); // "World"
Instanz erzeugen ohne new
Type t = typeof(List);
object instance = Activator.CreateInstance(t); // parameterloser Konstruktor
// Mit Parameter
var list = (IList)Activator.CreateInstance(typeof(List), 100); // Capacity 100
Typen in Assembly laden
Assembly asm = Assembly.Load("MyPluginAssembly");
foreach (Type t in asm.GetExportedTypes())
{
if (typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface)
{
IPlugin plugin = (IPlugin)Activator.CreateInstance(t);
plugin.Initialize();
}
}
Performance & Caching
- Reflection ist langsamer als direkter Code (ca. 10-100x).
MethodInfo,PropertyInfocachen (statische Felder).- Für häufige Aufrufe: Delegaten via
Delegate.CreateDelegateoder Expression Trees kompilieren (Func<T, TResult>). GetCustomAttributesData()(nur Metadaten) ist schneller alsGetCustomAttributes()(instanziiert Attribute).
Sicherheit
Reflection kann private Member zugreifen (BindingFlags.NonPublic | BindingFlags.Instance). In Sandbox-Umgebungen eingeschränkt (ReflectionPermission).
C Sprache
- C# Hello World – Ihre erste C#-Anwendung erstellen
- C# Keywords und Identifiers verstehen: Regeln, Listen und Best Practices
- C# Variablen & Primitive Datentypen meistern: Der komplette Guide
- C# Operatoren – Umfassender Leitfaden zu Operatoren in C#
- C# Bitweise und Bit-Shift-Operatoren meistern: Umfassender Leitfaden
- C# Grundlagen: Eingabe und Ausgabe Essentials
- C# Ausdrücke, Anweisungen & Blöcke: Umfassender Leitfaden mit Beispielen
- C# Kommentare meistern: Arten, Best Practices und XML-Dokumentation
- C# Break Statement: Wie und wann man es einsetzt
- C# Continue Statement meistern: Schleifeniterationen effektiv überspringen