Einleitung: wenn der Code "ich weiß nicht" sagt
\nStellen Sie sich vor: Sie schreiben in C# eine Bibliothek zur Serialisierung. Sie haben eine Methode Serialize<T>(T obj), die jedes Objekt in einen String umwandeln kann. Alles ist wunderbar, solange Sie sie mit einem konkreten Typ aufrufen: Serialize<User>(user). Aber was tun, wenn der Typ des Objekts erst zur Laufzeit des Programms bekannt wird?
Dies ist eine klassische Aufgabe, die tausende Entwickler auf Stack Overflow stellen: „How do I call a generic method using a Type variable?“. Auf den ersten Blick scheint die Lösung einfach, aber C# ist eine streng typisierte Sprache, und man kann nicht einfach eine Typvariable in die spitzen Klammern einsetzen.
\n\nIn diesem Tutorial werden wir durchgehen, wie man generische Methoden korrekt über C#-Reflexion mit Hilfe von MakeGenericMethod aufruft. Sie lernen nicht nur die Syntax, sondern auch, wann dies wirklich nötig ist und wann Sie besser nach Alternativen suchen sollten.
Warum kann man nicht einfach Method<type>() schreiben?
\nLassen Sie uns gleich mit den Illusionen aufräumen. Der folgende Code wird nicht kompilieren:
\nType runtimeType = someObject.GetType();\n// Kompilierungsfehler: "Der Typ 'runtimeType' ist ungültig"\nSomeMethod<runtimeType>();\n\n\nWarum? Weil generische Parameter in C# Metadaten zur Kompilierzeit sind. Der Compiler muss genau wissen, mit welchem Typ er arbeitet, um Code zu generieren. Eine Type-Variable ist ein Objekt, das nur zur Laufzeit existiert. Für den Compiler ist es einfach eine Variable, kein Typ.
Die Lösung liegt im Bereich der Reflexion – einem Mechanismus, der es erlaubt, Member von Typen zur Laufzeit zu untersuchen und aufzurufen.
\n\nSchritt-für-Schritt-Tutorial: Aufruf einer generischen Methode über Type
\nBetrachten wir die Aufgabe an einem konkreten Beispiel. Angenommen, wir haben einen Dienst zur Datenverarbeitung:
\npublic class DataProcessor\n{\n public string Process<T>(T data)\n {\n return $"Verarbeitet {typeof(T).Name}: {data}";\n }\n}\n\n\nWir möchten Process<T> aufrufen, wenn der Typ T erst zur Laufzeit bekannt ist, z.B. von typeof(string) oder someObject.GetType().
Schritt 1: MethodInfo für die generische Methode abrufen
\nZuerst müssen wir ein Objekt erhalten, das unsere Methode repräsentiert:
\nDataProcessor processor = new DataProcessor();\nType processorType = typeof(DataProcessor);\n\n// Methode nach Namen suchen. Wichtig: BindingFlags angeben, wenn die Methode nicht public ist\nMethodInfo? methodInfo = processorType.GetMethod("Process");\n\n\nWichtig! Wenn Sie mehrere Überladungen der Methode haben, müssen Sie die Suche mit GetMethods() und Filterung präzisieren. In unserem Fall gibt es nur eine Methode – einfach.
Schritt 2: Generische Methode mit MakeGenericMethod in eine konkrete umwandeln
\nHier ist er, der Hauptdarsteller des Artikels – die Methode MakeGenericMethod. Sie nimmt ein Array von Typen entgegen und gibt eine konstruierte (konkrete) Methode zurück:
Type runtimeType = typeof(int); // oder jeder andere dynamisch ermittelte Typ\nMethodInfo? genericMethod = methodInfo?.MakeGenericMethod(runtimeType);\n\n\nJetzt ist genericMethod eine vollwertige Methode Process<int>, bereit zum Aufruf.
Schritt 3: Methode über Invoke aufrufen
\nDer finale Akkord – die Verwendung von Invoke:
object? result = genericMethod?.Invoke(processor, new object[] { 42 });\nConsole.WriteLine(result); // Gibt aus: "Verarbeitet Int32: 42"\n\n\nBeachten Sie:
\n- \n
- Der erste Parameter von
Invokeist die Objektinstanz (für statische Methoden –null). \n - Der zweite Parameter ist ein Array der Methodenargumente. Auch wenn es nur ein Argument gibt, muss es in einem Array sein. \n
- Das Ergebnis wird als
object?zurückgegeben – Sie müssen es möglicherweise in den gewünschten Typ umwandeln. \n