我正在尝试创建一个 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;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top