1

If I want to call a generic method through reflection, I can easily use this technique, unless:

  1. The method can only be distinguished from another by its parameters.
  2. The method has a parameter that's type is one of the method's type parameters.

How do I specify a generic parameter in the Type[] array when calling Type.GetMethod(string, Type[])?

Example:

public class Example
{
    //This is the one I want to call.
    public void DoSomething<T>(T t) { ... }

    public void DoSomething(Foo foo) { ... }

    public void CallDoSomething(Type type, object value)
    {
        MethodInfo method = typeof(Example)
        .GetMethod("DoSomething", new Type[] {/* what do i put here? */ });

        MethodInfo generic = method.MakeGenericMethod(type);
        generic.Invoke(this, value);
    }
Community
  • 1
  • 1
AlphaModder
  • 3,266
  • 2
  • 28
  • 44
  • It would really help if you gave us more information about what you're trying to achieve. You quite possibly want to call `GetMethods` and then find the right one from there. – Jon Skeet Jun 27 '15 at 07:49
  • @JonSkeet Maybe an example will help. I'll add one. – AlphaModder Jun 27 '15 at 07:51

2 Answers2

1

You could do something like this:

MethodInfo method = typeof(Example)
    .GetMethods().First(mi => mi.Name == "DoSomething" && mi.IsGenericMethod);

Depending on how many method overloads you have, you might have to make the predicate more specific.

poke
  • 369,085
  • 72
  • 557
  • 602
1

I'll give you the full "thing" I use when I have to find a Queryable.Select<TSource, TResult> Method (IQueryable<TSource>, Expression<Func<TSource, TResult>>) method... It is quite complex and checks nearly all:

MethodInfo selectMethod = (from x in typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                           where x.Name == "Select" && x.IsGenericMethod
                           let pars = x.GetParameters()
                           where pars.Length == 2
                           let args = x.GetGenericArguments()
                           where args.Length == 2 &&
                               pars[0].ParameterType == typeof(IQueryable<>).MakeGenericType(args[0]) &&
                               pars[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(args))
                           select x).Single();

You can easily use it as a template.

Note that the return type isn't checked, because there is no overload for return types. The fact that the method is static and public is checked by the GetMethods(). I check number of parameters, number of generic arguments, type of parameters. Then I use the Single() to be sure that there is only one method. This should be future-proof: even if Microsoft added another Queryable.Select method, it would be "different".

In your specific case:

MethodInfo method = (from x in typeof(Example).GetMethods(BindingFlags.Instance | BindingFlags.Public)
                     where x.Name == "DoSomething" && x.IsGenericMethod
                     let pars = x.GetParameters()
                     where pars.Length == 1
                     let args = x.GetGenericArguments()
                     where args.Length == 1 &&
                         pars[0].ParameterType == args[0]
                     select x).Single();
xanatos
  • 109,618
  • 12
  • 197
  • 280