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>() { //... } }
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.
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.
MethodInfo method = typeof(Foo). GetMethod("MyGenericMethod"); method = method. MakeGenericMethod(t); method. Invoke(this, new object[0]);
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With