Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use reflection to call a generic method?

What's the best way to call a generic method when the type parameter isn't known at compile time, but instead is obtained dynamically at runtime?

Consider the following sample code - inside the Example() method, what's the most concise way to invoke GenericMethod<T>() using the Type stored in the myType variable?

public class Sample {     public void Example(string typeName)     {         Type myType = FindType(typeName);          // What goes here to call GenericMethod<T>()?         GenericMethod<myType>(); // This doesn't work          // What changes to call StaticMethod<T>()?         Sample.StaticMethod<myType>(); // This also doesn't work     }      public void GenericMethod<T>()     {         // ...     }      public static void StaticMethod<T>()     {         //...     } } 
like image 234
Bevan Avatar asked Oct 24 '08 05:10

Bevan


People also ask

How do you call a generic using reflection?

You need to use reflection to get the method to start with, then "construct" it by supplying type arguments with MakeGenericMethod: MethodInfo method = typeof(Sample). GetMethod(nameof(Sample. GenericMethod)); MethodInfo generic = method.

Do generics use reflection?

Because the Common Language Runtime (CLR) has access to generic type information at run time, you can use reflection to obtain information about generic types in the same way as for non-generic types.

How do you call a generic function in C#?

MethodInfo method = typeof(Foo). GetMethod("MyGenericMethod"); method = method. MakeGenericMethod(t); method. Invoke(this, new object[0]);


2 Answers

You need to use reflection to get the method to start with, then "construct" it by supplying type arguments with MakeGenericMethod:

MethodInfo method = typeof(Sample).GetMethod(nameof(Sample.GenericMethod)); MethodInfo generic = method.MakeGenericMethod(myType); generic.Invoke(this, null); 

For a static method, pass null as the first argument to Invoke. That's nothing to do with generic methods - it's just normal reflection.

As noted, a lot of this is simpler as of C# 4 using dynamic - if you can use type inference, of course. It doesn't help in cases where type inference isn't available, such as the exact example in the question.

like image 188
Jon Skeet Avatar answered Sep 21 '22 08:09

Jon Skeet


Just an addition to the original answer. While this will work:

MethodInfo method = typeof(Sample).GetMethod("GenericMethod"); MethodInfo generic = method.MakeGenericMethod(myType); generic.Invoke(this, null); 

It is also a little dangerous in that you lose compile-time check for GenericMethod. If you later do a refactoring and rename GenericMethod, this code won't notice and will fail at run time. Also, if there is any post-processing of the assembly (for example obfuscating or removing unused methods/classes) this code might break too.

So, if you know the method you are linking to at compile time, and this isn't called millions of times so overhead doesn't matter, I would change this code to be:

Action<> GenMethod = GenericMethod<int>;  //change int by any base type                                            //accepted by GenericMethod MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name); MethodInfo generic = method.MakeGenericMethod(myType); generic.Invoke(this, null); 

While not very pretty, you have a compile time reference to GenericMethod here, and if you refactor, delete or do anything with GenericMethod, this code will keep working, or at least break at compile time (if for example you remove GenericMethod).

Other way to do the same would be to create a new wrapper class, and create it through Activator. I don't know if there is a better way.

like image 22
Adrian Gallero Avatar answered Sep 22 '22 08:09

Adrian Gallero