Select Right Generic Method with Reflection

Viewed 18385

I want to select the right generic method via reflection and then call it.

Usually this is quite easy. For example

var method = typeof(MyType).GetMethod("TheMethod");
var typedMethod = method.MakeGenericMethod(theTypeToInstantiate);

However the issue start when there are different generic overloads of the method. For example the static-methods in the System.Linq.Queryable-class. There are two definitions of the 'Where'-method

static IQueryable<T> Where(this IQueryable<T> source, Expression<Func<T,bool>> predicate)
static IQueryable<T> Where(this IQueryable<T> source, Expression<Func<T,int,bool>> predicate)

This meand that GetMethod doesn't work, because it cannot destiguish the two. Therefore I want to select the right one.

So far I often just took the first or second method, depending on my need. Like this:

var method = typeof (Queryable).GetMethods().First(m => m.Name == "Where");
var typedMethod = method.MakeGenericMethod(theTypeToInstantiate);

However I'm not happy with this, because I make a huge assumption that the first method is the right one. I rather want to find the right method by the argument type. But I couldn't figure out how.

I tried it with passing the 'types', but it didn't work.

        var method = typeof (Queryable).GetMethod(
            "Where", BindingFlags.Static,
            null,
            new Type[] {typeof (IQueryable<T>), typeof (Expression<Func<T, bool>>)},
            null);

So has anyone an idea how I can find the 'right' generic method via reflection. For example the right version of the 'Where'-method on the Queryable-class?

13 Answers

I have a similar issue and I thought I would post my solution here. I'm trying to call several functions:

p.Foo<Klass1>(true)
p.Foo<Klass2>(true)
p.Foo<Klass3>(true)
bool k1 = p.Bar<Klass1>()
bool k2 = p.Bar<Klass2>()
bool k3 = p.Bar<Klass3>()

My solution:

public static TAction RemapGenericMember<TAction>(object parent, Type target, TAction func) where TAction : Delegate { 
    var genericMethod = func?.Method?.GetGenericMethodDefinition()?.MakeGenericMethod(target);
    if (genericMethod.IsNull()) {
        throw new Exception($"Failed to build generic call for '{func.Method.Name}' with generic type '{target.Name}' for parent '{parent.GetType()}'");
    }
    return (TAction)genericMethod.CreateDelegate(typeof(TAction), parent);
}

And now I can call:

foreach(var type in supportedTypes) {
   InvokeGenericMember<Action<bool>>(p, type, Foo<object>)(true);
   bool x = InvokeGenericMember<Function<bool>>(p, type, Bar<object>)();
}
var firstGenericParam = Type.MakeGenericMethodParameter(0);
var firstParam = typeof(IQueryable<>).MakeGenericType(firstGenericParam);
var funcType = typeof(Func<,>).MakeGenericType(firstGenericParam, typeof(bool));
//var funcType = typeof(Func<,,>).MakeGenericType(firstGenericParam, typeof(int), typeof(bool)); //for second version 
var secondParam = typeof(Expression<>).MakeGenericType(funcType);
var method = typeof(Queryable).GetMethod(nameof(Queryable.Where), new Type[] { firstParam, secondParam });
Related