Calling Generic Methods Using Reflection
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 and 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.
1using System;
2using System.Collections.Generic;
3
4namespace ExecuteGenericMethodByReflection
5{
6 public class PrinterA<T>
7 {
8 public void Print(IEnumerable<T> items)
9 {
10 Console.WriteLine();
11 foreach (var item in items)
12 {
13 Console.Write($"{item} ");
14 }
15 }
16 }
17}
1using System;
2using System.Collections.Generic;
3
4namespace ExecuteGenericMethodByReflection
5{
6 public class PrinterB
7 {
8 public void PrintSimple<T>(IEnumerable<T> items)
9 {
10 Console.WriteLine();
11
12 foreach (var item in items)
13 {
14 Console.Write($"{item} ");
15 }
16 Console.WriteLine();
17
18 }
19
20 public static void PrintPrefixAndSuffix<T>(IEnumerable<T> items, string prefix, string suffix)
21 {
22 Console.Write(prefix);
23 foreach (var item in items)
24 {
25 Console.Write($" {item} ");
26 }
27 Console.Write(suffix);
28 Console.WriteLine();
29 }
30
31 //This and the next method are overloads
32 public static void PrintPrefix<T>(IEnumerable<T> items, string prefix)
33 {
34 Console.Write(prefix);
35
36 foreach (var item in items)
37 {
38 Console.Write($" {item}");
39 }
40 Console.WriteLine();
41
42 }
43
44 public static void PrintPrefix<T>(IEnumerable<T> items, int prefix)
45 {
46 Console.WriteLine(prefix);
47
48 foreach (var item in items)
49 {
50 Console.Write($" {item}");
51 }
52 Console.WriteLine();
53 }
54
55 }
56}
And here is program where all the crazy reflection takes place.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5
6namespace ExecuteGenericMethodByReflection
7{
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 Program p = new Program();
13
14 List<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
15
16 p.ExecuteGenericInstanceMethodInNonGenericClass(numbers);
17 p.ExecuteGenericStaticMethodInNonGenericClass(numbers);
18 p.ExecuteGenericOverloadedStaticMethod(numbers);
19
20 p.ExecuteNonGenericMethodInGenericClass(numbers);
21
22 Console.WriteLine("\\n\\nPress any key to exit...");
23 Console.ReadKey();
24 }
25
26 private void ExecuteGenericInstanceMethodInNonGenericClass(object objectToPrint)
27 {
28 Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0];
29
30 PrinterB genericPrinter = new PrinterB();
31 MethodInfo printSimpleMethod = typeof(PrinterB).GetMethod("PrintSimple");
32 MethodInfo printSimpleMethodToExecute = printSimpleMethod.MakeGenericMethod(typeToPrint);
33
34 printSimpleMethodToExecute.Invoke(genericPrinter, new object[] { objectToPrint});
35 }
36
37 private void ExecuteGenericStaticMethodInNonGenericClass(object objectToPrint)
38 {
39 Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0];
40 MethodInfo printPrefixAndSuffixMethod = typeof(PrinterB).GetMethod("PrintPrefixAndSuffix");
41 MethodInfo genericprintPrefixAndSuffixMethodToExecute = printPrefixAndSuffixMethod.MakeGenericMethod(typeToPrint);
42
43 genericprintPrefixAndSuffixMethodToExecute.Invoke(null, new object[] { objectToPrint, "My Prefix", "My Suffix" });
44 }
45
46 // Executing an overloaded method is more diffcult, the method has to be identified by its parameters
47 private void ExecuteGenericOverloadedStaticMethod(object objectToPrint)
48 {
49 string prefixToPrint = "My Prefix";
50 Type overloadType = prefixToPrint.GetType();
51 Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0];
52 MethodInfo genricMethodToExecute = GetOverloadedMethod(typeToPrint, overloadType);
53 genricMethodToExecute.Invoke(null, new object[] { objectToPrint, prefixToPrint });
54 }
55
56 private void ExecuteNonGenericMethodInGenericClass(object objectToPrint)
57 {
58 Type typeToPrint = objectToPrint.GetType().GetGenericArguments()[0];
59
60 Type printerAType = typeof(PrinterA<>);
61 Type genericPrinterAType = printerAType.MakeGenericType(typeToPrint);
62
63 object genericPrinterAInstance = Activator.CreateInstance(genericPrinterAType);
64 MethodInfo printMethod = genericPrinterAType.GetMethod("Print");
65 printMethod.Invoke(genericPrinterAInstance, new object[] { objectToPrint });
66 }
67
68 private MethodInfo GetOverloadedMethod(Type typeToPassToGenericMethod, Type overloadType)
69 {
70 IEnumerable<MethodInfo> printMethods = typeof(PrinterB).GetMethods().Where(m => m.Name == "PrintPrefix");
71 MethodInfo printMethod = printMethods.Single(m => m.GetParameters().Any(p => p.ParameterType == overloadType));
72 MethodInfo genericPrintMethod = printMethod.MakeGenericMethod(typeToPassToGenericMethod);
73 return genericPrintMethod;
74 }
75 }
76}
Full source code here.