简体   繁体   中英

How do you call a generic method with out parameters by reflection?

Suppose I have a class like this, containing a generic method with an out parameter:

public class C
{
    public static void M<T>(IEnumerable<T> sequence, out T result)
    {
        Console.WriteLine("Test");
        result = default(T);
    }
}

From reading the answers to a couple of other questions ( How to use reflection to call generic Method? and Reflection on a static overloaded method using an out parameter ), I thought I might be able to invoke the method via reflection as follows:

// get the method
var types = new[] { typeof(IEnumerable<int>), typeof(int).MakeByRefType() };
MethodInfo mi = typeof(C).GetMethod(
    "M", BindingFlags.Static, Type.DefaultBinder, types, null);

// convert it to a generic method
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) });

// call it
var parameters = new object[] { new[] { 1 }, null };
generic.Invoke(null, parameters);

But mi is coming back null. I've tried using object instead of int in the types array but that doesn't work either.

How can I specify the types (needed for the out parameter) for a generic method before the call to MakeGenericMethod ?

You've passed parameters that will find M<T>(IEnumerable<int>, ref int) .
You need to find M(IEnumerable<T>, ref T) (the distinction between ref and out exists only in the C# language; reflection only has ref ).

I'm not sure how to pass that; you may need to loop through all methods to find it.

On an unrelated note, you need to pass more BindingFlags :

BindingFlags.Public | BindingFlags.Static

This will let you call the method:

MethodInfo mi = typeof(C).GetMethod("M");
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) });
var parameters = new object[] { new[]{1},null};
generic.Invoke(null, parameters);

And to get the out parameter:

Console.WriteLine((int)parameters[1]); //will get you 0(default(int)).

I'm still interested to know what the syntax is for specifying an array of template types, or if it's not possible

I don't think it's possible to pass that kind of detailed type specification to GetMethod[s] . I think if you have a number of such M s to look through, you have to get them all and then filter by the various properties of the MethodInfo s and contained objects, eg as much of this as is necessary in your particular case:

var myMethodM =
    // Get all the M methods
    from mi in typeof(C).GetMethods()
    where mi.Name == "M"

    // that are generic with one type parameter
    where mi.IsGenericMethod
    where mi.GetGenericArguments().Length == 1
    let methodTypeParameter = mi.GetGenericArguments()[0]

    // that have two formal parameters
    let ps = mi.GetParameters()
    where ps.Length == 2

    // the first of which is IEnumerable<the method type parameter>
    where ps[0].ParameterType.IsGenericType
    where ps[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
    where ps[0].ParameterType.GetGenericArguments()[0] == methodTypeParameter

    // the second of which is ref <the method type parameter>
    where ps[1].ParameterType.IsByRef
    where ps[1].ParameterType.GetElementType() == methodTypeParameter

    select mi;

This is a well known-problem; to find the method, you need to know its type parameter, but you can't know its type parameter without knowing the method first...

An obvious but inelegant solution is to loop through all methods until you find the right one.

Another option is to take advantage of the Linq Expression API:

public static MethodInfo GetMethod(Expression<Action> expr)
{
    var methodCall = expr.Body as MethodCallExpression;
    if (methodCall == null)
        throw new ArgumentException("Expression body must be a method call expression");
    return methodCall.Method;
}


...

int dummy;
MethodInfo mi = GetMethod(() => C.M<int>(null, out dummy));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM