How do I use reflection to call a generic method?
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.
Reflection: invoke a method with generic parameter
The problem is that GetMethod
finds multiple methods with that mane before you even tell it which overload you want. The overload of GetMethod
that allows you to pass in an array of types works for non-generic methods, but since the parameters are generic you can't use it.
You need to call GetMethods
and filter down to the one you want:
var methods = typeof(ObjectType).GetMethods();
var method = methods.Single(mi => mi.Name=="Create" && mi.GetParameters().Count()==5);
method.MakeGenericMethod(new Type[] { typeof(Item), typeof(TKparent) })
.Invoke(_objectInstance, new object[] { parent, name, _language, true, false });
You could obviously inline all of that if you want, but it makes debugging easier if you separate it into separate lines.
Call a Generic method by reflection in java
Generics are erased at compile time, they only provide extra information to the compiler to determine errors. They do not actually change the signature of the method in the .class
file.
This means that you call a generic method by reflection in Java exactly the same way as you would call a non-generic method in Java, except that instead of specifying a type of T
, you would specify a type of Object
.
There are so many tutorials on how to call a regular method by reflection that I hesitate to add yet another; however, if you really need direction on how to call a method by reflection, please add a comment below and I'll add the necessary code.
If you find that things are not working as expected, you can always run javap
on the compiled class file to verify that you are using the right objects in the argument list. It might be possible that if you specify a <T extends List>
type generic signature, the resulting parameter object might actually be a List
object.
How to call a generic method through reflection
The Cast extension method lives on the class Enumerable, and you need to call MakeGenericMethod:
typeof(System.Linq.Enumerable)
.GetMethod("Cast", new []{typeof(System.Collections.IEnumerable)})
.MakeGenericMethod(typeof(S))
.Invoke(null, new object[] { oObjectType })
update: Because the method is static, the first parameter to Invoke should be null
Call generic method by reflection. System.ArgumentException happens
In this line:
var generic = method.MakeGenericMethod(type);
You are creating a generic method of type type
, which is MyRequest
.
So, eventually you are using MyRequest
as TResponse
.
But what you actually want to do is you want to pass MyResponse
as TResponse
.
You can do the following in order to be able to call this dynamically:
- get the interface
IMyRequest<>
which is your request is implementing - get the only generic argument of this interface, which will be
TResponse
This is how the code might look like, but you need to add some checks on types and valid error handling here:
var type = request.GetType();
var responseType = type.GetInterfaces() // [IRequest<MyResponse>]
.Single(i => i.GetGenericTypeDefinition() == typeof(IRequest<>)) // IRequest<MyResponse>
.GetGenericArguments() // [MyResponse]
.Single(); // MyResponse
var method = mediator.GetType().GetMethod("Send");
var generic = method.MakeGenericMethod(responseType); // note that responseType is used here
var response = generic.Invoke(mediator, new object[] { request });
After all, are you sure that you want to bind your response to a specific definition of a request? I don't know your architecture and what you are trying to achieve, but, perhaps, this can be a more agile solution:
public interface IRequest
{
}
public interface IMediator
{
TResponse Send<TRequest, TResponse>(IRequest request);
}
public class MyRequest : IRequest
{
}
public class MyResponse
{
}
public class Mediator : IMediator
{
public TResponse Send<TRequest, TResponse>(IRequest request)
{
Console.WriteLine("Processing...");
return default(TResponse);
}
}
Call a local generic method by reflection
Jon Skeets answer will work for your problem too.
I only changed the signature to match your requirements:
var repository = new Repository();
repository.Store<Foo>(xs => xs.Count());
int Compute<M>(string[] source) => repository.Fetch<M>().Invoke(source);
// Call Compute<M>
var runtimeKnownTime = typeof(Foo);
var computeResult = InvokeHelper(Compute<object>, new[] { "A", "B" }, runtimeKnownTime);
Console.WriteLine(computeResult);
This uses the following implementation of InvokeHelper
:
// This code was created by Jon Skeet : https://stackoverflow.com/a/43349127/2729609
// I only changed Action<int> to Func<int, int> and changed the return type.
private static int InvokeHelper(Func<string[], int> int32Func, object data, Type type)
{
// You probably want to validate that it really is a generic method...
var method = int32Func.Method;
var genericMethod = method.GetGenericMethodDefinition();
var concreteMethod = genericMethod.MakeGenericMethod(type);
return (int)concreteMethod.Invoke(int32Func.Target, new[] { data });
}
DEMO
BUT I don't see the need to use this hack. You don't need the generic type in your case.
Change the repository to:
public class Repository
{
private Dictionary<Type, object> _store = new Dictionary<Type, object>();
public void Store(Type id, Func<string[], int> value)
{
_store[id] = value;
}
// optional
public void Store<T>(Func<string[], int> value) => this.Store(typeof(T), value);
public Func<string[], int> Fetch(Type id)
{
return (Func<string[], int>)_store[id];
}
// optional
public Func<string[], int> Fetch<T>() => this.Fetch(typeof(T));
}
And you can use it without generics:
var repository = new Repository();
repository.Store(typeof(Foo), xs => xs.Count());
int Compute(Type id, string[] source) => repository.Fetch(id).Invoke(source);
// Call Compute<M>
var runtimeKnownTime = typeof(Foo);
Console.WriteLine(Compute(runtimeKnownTime, new[] { "A", "B" }));
If you want, create generic overloads for the methods Fetch
and Store
that call the shown implementation using typeof(T)
. I markted this method with optional
in my sample implemenation.
How do you call a generic method with out parameters by reflection?
I'm still interested to know what the syntax is for specifying an array of template types, or if it's not possible
I don't think it's possible to pass that kind of detailed type specification to GetMethod[s]
. I think if you have a number of such M
s to look through, you have to get them all and then filter by the various properties of the MethodInfo
s and contained objects, eg as much of this as is necessary in your particular case:
var myMethodM =
// Get all the M methods
from mi in typeof(C).GetMethods()
where mi.Name == "M"
// that are generic with one type parameter
where mi.IsGenericMethod
where mi.GetGenericArguments().Length == 1
let methodTypeParameter = mi.GetGenericArguments()[0]
// that have two formal parameters
let ps = mi.GetParameters()
where ps.Length == 2
// the first of which is IEnumerable<the method type parameter>
where ps[0].ParameterType.IsGenericType
where ps[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
where ps[0].ParameterType.GetGenericArguments()[0] == methodTypeParameter
// the second of which is ref <the method type parameter>
where ps[1].ParameterType.IsByRef
where ps[1].ParameterType.GetElementType() == methodTypeParameter
select mi;
How to call a generic extension method with reflection?
The extension method isn't attached to the type Form
, it's attached to the type MyClass
, so grab it off that type:
MethodInfo methodInfo = typeof(MyClass).GetMethod("GenericExtension",
new[] { typeof(Form), typeof(string) });
Related Topics
How to Update the Gui from Another Thread
How to Implement Custom Jsonconverter in Json.Net
Convert List≪Derivedclass≫ to List≪Baseclass≫
Automating the Invokerequired Code Pattern
What's the @ in Front of a String in C#
How to Translate Between Windows and Iana Time Zones
Best Way to Implement Keyboard Shortcuts in a Windows Forms Application
String Was Not Recognized as a Valid Datetime " Format Dd/Mm/Yyyy"
How to Use Reflection to Call a Generic Method
Deserializing Polymorphic Json Classes Without Type Information Using Json.Net
How to Read and Parse an Xml File in C#
What Does the =≫ Operator Mean in a Property
In C#, Why Is String a Reference Type That Behaves Like a Value Type
No Connection Could Be Made Because the Target Machine Actively Refused It