Full source code here.
Accessing generic methods by reflection is not easy. A while ago I needed to do just that and found relatively little information out there. So I dug in a figured it out for myself.
Here are some of the possible ways that you could execute generic methods by reflection –
- Execute a Generic Instance Method in a Non-Generic Class
- Execute Generic Static Method In a Non-Generic Class
- Execute Generic Overloaded Static Method
- Execute NonGeneric Method in a Generic Class
There are other variations, but you should be able to figure out how to write them based on the ones shown here.
In the classes PrinterA
and PrinterB
, there are a variety of generic and one non-generic methods that I will call using reflection from Program
.
The code will explain things better than I can, so here is the listing.
using System; using System.Collections.Generic; namespace ExecuteGenericMethodByReflection { public class PrinterA<T> { public void Print(IEnumerable<T> items) { Console.WriteLine(); foreach (var item in items) { Console.Write($"{item} "); } } } }
using System; using System.Collections.Generic; namespace ExecuteGenericMethodByReflection { public class PrinterB { public void PrintSimple<T>(IEnumerable<T> items) { Console.WriteLine(); foreach (var item in items) { Console.Write($"{item} "); } Console.WriteLine(); } public static void PrintPrefixAndSuffix<T>(IEnumerable<T> items, string prefix, string suffix) { Console.Write(prefix); foreach (var item in items) { Console.Write($" {item} "); } Console.Write(suffix); Console.WriteLine(); } //This and the next method are overloads public static void PrintPrefix<T>(IEnumerable<T> items, string prefix) { Console.Write(prefix); foreach (var item in items) { Console.Write($" {item}"); } Console.WriteLine(); } public static void PrintPrefix<T>(IEnumerable<T> items, int prefix) { Console.WriteLine(prefix); foreach (var item in items) { Console.Write($" {item}"); } Console.WriteLine(); } } }
And here is program where all the crazy reflection takes place.
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; namespace ExecuteGenericMethodByReflection { class Program { static void Main(string[] args) { Program p = new Program(); List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 }; p.ExecuteGenericInstanceMethodInNonGenericClass(numbers); p.ExecuteGenericStaticMethodInNonGenericClass(numbers); p.ExecuteGenericOverloadedStaticMethod(numbers); p.ExecuteNonGenericMethodInGenericClass(numbers); Console.WriteLine("\n\nPress any key to exit..."); Console.ReadKey(); } private void ExecuteGenericInstanceMethodInNonGenericClass(object objectToPrint) { Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0]; PrinterB genericPrinter = new PrinterB(); MethodInfo printSimpleMethod = typeof(PrinterB).GetMethod("PrintSimple"); MethodInfo printSimpleMethodToExecute = printSimpleMethod.MakeGenericMethod(typeToPrint); printSimpleMethodToExecute.Invoke(genericPrinter, new object[] { objectToPrint}); } private void ExecuteGenericStaticMethodInNonGenericClass(object objectToPrint) { Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0]; MethodInfo printPrefixAndSuffixMethod = typeof(PrinterB).GetMethod("PrintPrefixAndSuffix"); MethodInfo genericprintPrefixAndSuffixMethodToExecute = printPrefixAndSuffixMethod.MakeGenericMethod(typeToPrint); genericprintPrefixAndSuffixMethodToExecute.Invoke(null, new object[] { objectToPrint, "My Prefix", "My Suffix" }); } // Executing an overloaded method is more diffcult, the method has to be identified by its parameters private void ExecuteGenericOverloadedStaticMethod(object objectToPrint) { string prefixToPrint = "My Prefix"; Type overloadType = prefixToPrint.GetType(); Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0]; MethodInfo genricMethodToExecute = GetOverloadedMethod(typeToPrint, overloadType); genricMethodToExecute.Invoke(null, new object[] { objectToPrint, prefixToPrint }); } private void ExecuteNonGenericMethodInGenericClass(object objectToPrint) { Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0]; Type printerAType = typeof(PrinterA<>); Type genericPrinterAType = printerAType.MakeGenericType(typeToPrint); object genericPrinterAInstance = Activator.CreateInstance(genericPrinterAType); MethodInfo printMethod = genericPrinterAType.GetMethod("Print"); printMethod.Invoke(genericPrinterAInstance, new object[] { objectToPrint }); } private MethodInfo GetOverloadedMethod(Type typeToPassToGenericMethod, Type overloadType) { IEnumerable<MethodInfo> printMethods = typeof(PrinterB).GetMethods().Where(m => m.Name == "PrintPrefix"); MethodInfo printMethod = printMethods.Single(m => m.GetParameters().Any(p => p.ParameterType == overloadType)); MethodInfo genericPrintMethod = printMethod.MakeGenericMethod(typeToPassToGenericMethod); return genericPrintMethod; } } }
Full source code here.