2009-09-23 52 views
3

我正在尝试创建一个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)

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

+1

有萨姆藏红花相关答案在这里:http://stackoverflow.com/questions/1452261/how-do-i-invoke-an -extension-方法-使用反射/。问题是关于扩展方法,但答案仍然与您的问题相关,因为所讨论的扩展方法(System.Enumerable.Where)与您的方法类似,是一种重载泛型方法。 – Joren 2009-09-23 12:50:09

回答

5

您需要使用 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(); 
} 
+0

正确,但首先我需要找到正确的MethodInfo来创建实现。 Enumerable.Average有过载,需要Func ,Func ,Func 等。 – dkackman 2009-09-23 12:45:49

+0

查看我的更新回答 – 2009-09-23 13:10:53

0

感谢@Joren:OK,我误解了问题...这方法应该做你想要什么。这个例子根据参数计数来区分,但它让我朝着正确的方向发展。

的作品的选择是

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; 
1

既然你正在构建的表达,而不是直接执行,你可以跳过MethodInfo的步骤,并且使用Expression.Call重载需要一个方法直奔MethodCallExpression名称而不是MethodInfo。

var call = Expression.Call(typeof(Enumerable), 
      "Average", 
      new Type[] { typeof(MyTSource) }, 
      enumerableParameter, lambdaParameter 
       ); 
+0

嗯。我错过了Call的超载。我得看一看。 – dkackman 2009-09-23 13:11:07

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(); 
}