4

我正在尝试创建一个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>where的特定重载argType == typeof(int)

我很难过,任何帮助表示赞赏。

4

4 回答 4

6

您需要使用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();
}
于 2009-09-23T12:43:48.930 回答
1

由于您正在构建一个表达式而不是直接执行,因此您可以跳过 MethodInfo 步骤并使用采用方法名称而不是 MethodInfo 的 Expression.Call 重载直接进入 MethodCallExpression。

var call = Expression.Call(typeof(Enumerable),
             "Average",
            new Type[] { typeof(MyTSource) },
            enumerableParameter, lambdaParameter
                );
于 2009-09-23T13:04:19.077 回答
1

这是如何做到的:

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();
}
于 2009-09-23T13:22:39.433 回答
0

感谢@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;
于 2009-09-23T13:01:19.223 回答