如何使用反射找到特定的通用重载?
-
13-09-2019 - |
题
我正在尝试创建一个 Expression
这将调用特定的通用重载方法(Enumerable.Average
在我的第一个测试用例中)。然而,具体的类型绑定直到运行时才知道,所以我需要使用 Reflection
找到并创建正确的通用方法( Expression
是从解析的文本创建的)。
因此,如果我在运行时知道我想要找到这个特定的重载:
public static double Average<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
我该如何解决这个特定问题 MethodInfo
使用反射?
到目前为止,我有以下选择声明:
MethodInfo GetMethod(Type argType, Type returnType)
{
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
where method.Name == "Average" &&
method.ContainsGenericParameters &&
method.GetParameters().Length == 2 &&
// and some condition where method.GetParameters()[1] is a Func that returns type argType
method.ReturnType == returnType
select method;
Debug.Assert(methods.Count() == 1);
return methods.FirstOrDefault();
}
上面将其范围缩小到三个重载,但我想反思并找到需要 Func<TSource, int>
在哪里 argType == typeof(int)
.
我很困惑,感谢任何帮助。
解决方案
你需要使用 MethodInfo.MakeGenericMethod
编辑:好吧,我误解了这个问题......这个方法应该做你想做的:
MethodInfo GetMethod(Type argType, Type returnType)
{
var enumerableType = typeof(IEnumerable<>).MakeGenericType(new Type[] { argType });
Console.WriteLine(enumerableType);
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
let parameters = method.GetParameters()
let genParams = method.GetGenericArguments()
where method.Name == "Average" &&
method.ContainsGenericParameters &&
parameters.Length == 2 &&
parameters[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>) &&
parameters[1].ParameterType.GetGenericArguments()[1] == argType &&
method.ReturnType == returnType
select method;
return methods.FirstOrDefault();
}
其他提示
由于您正在构建表达式而不是直接执行,因此您可以跳过 MethodInfo 步骤并使用采用方法名称而不是 MethodInfo 的 Expression.Call 重载直接转到 MethodCallExpression。
var call = Expression.Call(typeof(Enumerable),
"Average",
new Type[] { typeof(MyTSource) },
enumerableParameter, lambdaParameter
);
操作方法如下:
static MethodInfo GetMethod(Type argType, Type returnType)
{
var methods = from m in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
where m.ContainsGenericParameters
&& m.Name == "Average"
&& m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>)
&& m.GetParameters()[1].ParameterType.GetGenericArguments()[1] == returnType
select m;
return methods.First();
}
感谢@Joren 提供的链接提示。该示例根据参数计数进行区分,但它让我找到了正确的方向。
有效的选择是
var methods = from method in typeof(Enumerable).GetMethods(BindingFlags.Public | BindingFlags.Static)
where method.Name == Name &&
method.ContainsGenericParameters &&
method.ReturnType == returnType &&
method.GetParameters().Length == 2 &&
method.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2 &&
method.GetParameters()[1].ParameterType.GetGenericArguments()[1] == argType
select method;
不隶属于 StackOverflow