How to call generic method with a given Type object? [duplicate]
Asked Answered
C

3

61

I want to call my generic method with a given type object.

void Foo(Type t)
{
     MyGenericMethod<t>();
}

obviously doesn't work.

How can I make it work?

Citrin answered 10/9, 2009 at 22:47 Comment(1)
Just because it's hard to find: Using dynamic saves you from all the error-prone reflection work. The best answer is there in the referenced question: https://mcmap.net/q/45410/-how-do-i-call-a-generic-method-using-a-type-variableTracheitis
I
62

Your code sample won't work, because the generic method expects a type identifier, not a an instance of the Type class. You'll have to use reflection to do it:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = typeof (Example).GetMethod("Test");
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

Do keep in mind that this is very brittle, I'd rather suggest finding another pattern to call your method.

Another hacky solution (maybe someone can make it a bit cleaner) would be to use some expression magic:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = GetMethod<Example>(x => x.Test<object>());
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public static MethodInfo GetMethod<T>(Expression<Action<T>> expr)
    {
        return ((MethodCallExpression) expr.Body)
            .Method
            .GetGenericMethodDefinition();
    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

Note passing the 'object' type identifier as a generic type argument in the lambda. Couldn't figure out so quickly how to get around that. Either way, this is compile-time safe I think. It just feels wrong somehow :/

Insomnolence answered 10/9, 2009 at 22:56 Comment(3)
My bad, I changed around some names (tested in a default C# console app, so the class is called Program ;)) Fixed it for you, it should be the name of the class you want to call the method on.Insomnolence
Great idea with the Expressions. I also can not think of a way to refer to a generic method without specifying at least a generic dummy argument..Citrin
Thank you for providing the "hacky" expressions (ala the best way of doing this IMO) as a starting point.Venavenable
R
19

You need to use reflection, unfortunately (for the reasons Jared mentioned). For example:

MethodInfo method = typeof(Foo).GetMethod("MyGenericMethod");
method = method.MakeGenericMethod(t);
method.Invoke(this, new object[0]);

Obviously you'd want more error checking in reality :)


Side note: my local MSDN doesn't specify that the parameter from MakeGenericMethod is a parameter array, so I'd have expected to require:

method = method.MakeGenericMethod(new Type[] { t });

but it seems it is a parameter array in reality, and the online MSDN docs agree. Odd.

Riviera answered 10/9, 2009 at 22:51 Comment(8)
argghh! The Skeet got me beat :/Insomnolence
Thanks for reply, Jon. But I have already given the right method, why do I need to load them by name? Isn't there are more safe way which doesn't involve method names as strings?Citrin
Cody: I added another alternative in my answer (trying to beat the Skeet) which doesn't involve strings. It's not as clean as I want, but the idea is clear I think.Insomnolence
I wonder why there isn't a refactoring-safe way to pass method names around in C# programs. Can we blame Mr. Hejlsberg for that? :)Citrin
You're after the infamous infoof operator. It's on the list of desirable features, but it just hasn't got high enough yet...Riviera
This is not the first time where I would have needed such an operator. Where can I vote for it?Citrin
Umm that was me sorry. I mis-clicked and hit the wrong arrow. It won't let me change now. sorryUmmersen
@RobertLevy: Try now - I've edited the answer, so you should be able to change your vote. Not that it really matters.Riviera
A
-2

This approach will not work. The reason why is that Type is an object who's type is determined at runtime. However you are trying to use it to call a generic method. A generic method call's type is established at compile time. Hence a Type object can't ever be used for a type parameter on a generic method.

Averill answered 10/9, 2009 at 22:50 Comment(1)
Then what's the solution ? I am also into this topic so much. Thanks.Binucleate

© 2022 - 2024 — McMap. All rights reserved.