[英]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: 假设我有一个这样的类,包含带out参数的泛型方法:
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: 从阅读答案到其他几个问题( 如何使用反射调用泛型方法?和使用out参数反映静态重载方法 ),我想我可以通过反射调用方法,如下所示:
// 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. 但是
mi
回来了。 I've tried using object
instead of int
in the types
array but that doesn't work either. 我尝试在
types
数组中使用object
而不是int
,但这也不起作用。
How can I specify the types (needed for the out parameter) for a generic method before the call to MakeGenericMethod
? 在调用
MakeGenericMethod
之前 ,如何为泛型方法指定类型(out参数所需)?
You've passed parameters that will find M<T>(IEnumerable<int>, ref int)
. 您已经传递了将找到
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
). 你需要找到
M(IEnumerable<T>, ref T)
( ref
和out
之间的区别只存在于C#语言中;反射只有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
:
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: 并获得out参数:
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]
. 我认为不可能将这种详细的类型规范传递给
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: 我想如果你有很多这样的
M
要查看,你必须得到它们然后按MethodInfo
的各种属性和包含的对象进行过滤,例如在你的特定情况下需要的大部分内容:
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: 另一个选择是利用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));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.