5

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!

Community
  • 1
  • 1
ldp
  • 360
  • 2
  • 11

2 Answers2

5

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>.

David Anderson
  • 13,558
  • 5
  • 50
  • 76
  • typeof (Enumerable).GetMember("Where")[0] as MethodInfo is enough. – ldp Sep 24 '11 at 13:02
  • I recommended that, but I posted the other method because that was the question. @Daniel A. White, You can. You either have to know the name of the class that defines the extension method, or look for it by checking for `ExtensionAttribute`. The way I've found is short is to navigate through the assemblies types and check if they have any types with `ExtensionAttribute`. If it does, I can look at its methods and check to see if the first `ParameterType` is the class it is supposed to extend (ie. `static void Foo(this Program)`) we would be looking for `Program` as the `ParameterType` – David Anderson Sep 24 '11 at 13:05
1

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.

Community
  • 1
  • 1
atanamir
  • 4,833
  • 3
  • 24
  • 20