Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invoke Enumerable.Where (or other overloaded generic method) using reflection

There are 2 overloads (or method signatures) of the "Where" method in Enumerable class:

namespace System.Linq {
    public static class Enumerable {
        public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
        public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate);
    }

So

var where = typeof(Enumerable).GetMethod("Where") 

throws an exception stating an ambiguous match because, of course, there is more than one method with the name "Where", so I tried to differentiate by the parameters:

var types = new[] { 
    typeof(IEnumerable<>), 
    typeof(Func<,>)};
var where = typeof(Enumerable).GetMethod("Where", types);

This however doesn't match either of the method signatures, and I'm not sure why.

Generalized question: How do you invoke an overloaded generic method via reflection without iterating over all the methods in the class w/ the same name (i.e., using System.Type.GetMethod(System.String, System.Type[])?

Please help me fix it! Thanks!

like image 440
ldp Avatar asked Sep 24 '11 10:09

ldp


People also ask

Can we invoke generic method using .NET reflection?

The first step to dynamically invoking a generic method with reflection is to use reflection to get access to the MethodInfo of the generic method. To do that simply do this: var methodInfo = typeof(ClassWithGenericMethod). GetMethod("MethodName");

How do you invoke a generic method?

To call a generic method, you need to provide types that will be used during the method invocation. Those types can be passed as an instance of NType objects initialized with particular . NET types.


2 Answers

You can't accomplish this with only GetMethod() because it has limitations with generics. This is how you would do it with GetMethod() properly.

Type enumerableType = typeof(Enumerable);
MemberInfo[] members = enumerableType.GetMember("Where*");
MethodInfo whereDef = (MethodInfo)members[0]; // Where<TSource>(IEnumerable<TSource, Func<TSource,Boolean>)
Type TSource = whereDef.GetGenericArguments()[0]; // TSource is the only generic argument
Type[] types = { typeof(IEnumerable<>).MakeGenericType(TSource), typeof(Func<,>).MakeGenericType(TSource, typeof(Boolean)) };
MethodInfo method = enumerableType.GetMethod("Where", types);

The best way is to just iterate over members since it already contains both MethodInfo definitions for Where<TSource>.

like image 172
David Anderson Avatar answered Oct 14 '22 00:10

David Anderson


You might be interested to see a code snippet I posted in this other answer:

It's a more general way to get any generic method via an extension method, with clean syntax that looks like:

var where = typeof(Enumerable).GetMethod(
  "Where", 
  typeof(IQueryable<Refl.T1>), 
  typeof(Expression<Func<Refl.T1, bool>>
);

Notice the Refl.T1 that takes the place of a generic type parameter.

like image 26
atanamir Avatar answered Oct 13 '22 22:10

atanamir