2

How do I call SomeObject.SomeGenericInstanceMethod<T>(T arg) ?

There are a few posts about calling generic methods, but not quite like this one. The problem is that the method argument parameter is constrained to the generic parameter.

I know that if the signature were instead

SomeObject.SomeGenericInstanceMethod<T>(string arg)

then I could get the MethodInfo with

typeof (SomeObject).GetMethod("SomeGenericInstanceMethod", new Type[]{typeof (string)}).MakeGenericMethod(typeof(GenericParameter))

So, How do I go about getting the MethodInfo when the regular arguments are of a generic type? Thanks!

Also, there may or may not be type constrains on the generic parameter.

smartcaveman
  • 41,281
  • 29
  • 127
  • 212
  • possible duplicate of [Select Right Generic Method with Reflection](http://stackoverflow.com/questions/3631547/select-right-generic-method-with-reflection) – nawfal Jan 17 '14 at 15:22

2 Answers2

11

You do it exactly the same way.

When you call MethodInfo.Invoke, you pass all the arguments in an object[] anyway, so it's not like you have to know the types at compile time.

Sample:

using System;
using System.Reflection;

class Test
{
    public static void Foo<T>(T item)
    {
        Console.WriteLine("{0}: {1}", typeof(T), item);
    }

    static void CallByReflection(string name, Type typeArg,
                                 object value)
    {
        // Just for simplicity, assume it's public etc
        MethodInfo method = typeof(Test).GetMethod(name);
        MethodInfo generic = method.MakeGenericMethod(typeArg);
        generic.Invoke(null, new object[] { value });
    }

    static void Main()
    {
        CallByReflection("Foo", typeof(object), "actually a string");
        CallByReflection("Foo", typeof(string), "still a string");
        // This would throw an exception
        // CallByReflection("Foo", typeof(int), "oops");
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    Will this still work if there are multiple overloads for the method named "name"? – smartcaveman Jan 19 '11 at 17:39
  • 1
    @smartcaveman: No, you'd need to work out which one to call. Calling `GetMethod(string, Type[])` can get quite tricky when the parameter types are generic - I usually use `GetMethods` in conjunction with a LINQ query to find the right method. – Jon Skeet Jan 19 '11 at 17:41
  • Something like: typeof(Test).GetMethods(BindingFlags.Instance).Where(x=>x.IsGenericMethodDefinition & x.Name==name) ? – smartcaveman Jan 19 '11 at 17:46
  • 1
    @smartcaveman: Well that wouldn't help if there were *two* generic methods with the same name. Basically I can't help you much here, because I don't know how you *want* to be able to identify the right method. Work out how you'd tell them apart manually, and write a query for it. – Jon Skeet Jan 19 '11 at 17:48
  • How do you determine that a ParameterInfo is generic? – smartcaveman Jan 19 '11 at 17:49
  • 1
    @smartcaveman: Try ParameterInfo.ParameterType.IsGenericType. – Jon Skeet Jan 19 '11 at 17:55
  • Thanks... I realized that was a bit of a different question, so.. http://stackoverflow.com/questions/4738826/how-to-determine-if-parameterinfo-is-of-generic-type – smartcaveman Jan 19 '11 at 17:58
2

You do it exactly the same way, but pass an instance of your object:

typeof (SomeObject).GetMethod(
       "SomeGenericInstanceMethod", 
        yourObject.GetType())  
                 // Or typeof(TheClass), 
                 // or typeof(T) if you're in a generic method
   .MakeGenericMethod(typeof(GenericParameter))

The MakeGenericMethod method only requires you to specify the generic type parameters, not the method's arguments.

You'd pass the arguments in later, when you call the method. However, at this point, they're passing as object, so it again doesn't matter.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 1
    Note that the GetMethod call may fail if `yourObject` is a *subtype* of the required one, as in my first example. The subtype may not satisfy the constraints - for example, consider `Foo(T item) where T : new()` called as `Foo("hello")`. We *don't* want to call `Foo("hello")` as string doesn't have a parameterless constructor. – Jon Skeet Jan 19 '11 at 17:44