How to Use Reflection to Call a Generic Method

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 Ms to look through, you have to get them all and then filter by the various properties of the MethodInfos 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



Leave a reply



Submit