2010-12-14 75 views
9

我有这种类型,其中包含两个通用方法的重载。我喜欢使用反射来检索其中一个重载(使用Func<T>参数)。但问题是,我无法找到正确的参数类型来提供Type.GetMethod(string, Type[])方法。检索通用方法的正确过载的方法信息

这里是我的类定义:

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

这就是我想出的,可惜没有更迭:

[TestMethod] 
public void Test1() 
{ 
    Type parameterType = typeof(Func<>); 

    var method = typeof(Foo).GetMethod("Bar", new Type[] { parameterType }); 

    Assert.IsNotNull(method); // Fails 
} 

我怎样才能得到的一般方法的MethodInfo我知道参数?

回答

9

为什么不使用表达式树?这使得它更容易:

public static MethodInfo GetMethod<T>(
    Expression<Action<T>> methodSelector) 
{ 
    var body = (MethodCallExpression)methodSelector.Body; 
    return body.Method;  
} 

[TestMethod] 
public void Test1() 
{ 
    var expectedMethod = typeof(Foo) 
     .GetMethod("Bar", new Type[] { typeof(Func<>) }); 

    var actualMethod = 
     GetMethod<Foo>(foo => foo.Bar<object>((Func<object>)null) 
     .GetGenericMethodDefinition(); 

    Assert.AreEqual(expectedMethod, actualMethod); 
} 
+0

哇..很酷。很棒!而这么小的代码。 – Anne 2011-01-06 19:57:53

1

你需要指定使用MethodInfo.MakeGenericMethod.

但是具体类型,我应该指出,这获得正确的类型上调用MakeGenericMethod当你有一个重载的泛型方法是不容易的。

下面是一个例子:

var method = typeof(Foo) 
       .GetMethods() 
       .Where(x => x.Name == "Bar") 
       .Where(x => x.IsGenericMethod) 
       .Where(x => x.GetGenericArguments().Length == 1) 
       .Where(x => x.GetParameters().Length == 1) 
       .Where(x => 
        x.GetParameters()[0].ParameterType == 
        typeof(Action<>).MakeGenericType(x.GetGenericArguments()[0]) 
       ) 
       .Single(); 

method = method.MakeGenericMethod(new Type[] { typeof(int) }); 

Foo foo = new Foo(); 
method.Invoke(foo, new Func<int>[] {() => return 42; }); 
+0

这不会帮助。他无法获得公开的实例。 – SLaks 2010-12-14 19:43:02

+0

你能告诉我一个例子吗? – Anne 2010-12-14 19:43:28

+0

@SLaks:是的,这是可能的。我会举一个例子。 – jason 2010-12-14 19:53:44

1

我不认为可以做到这一点直接使用GetMethod。我怀疑你将不得不遍历所有叫Bar的方法,那么:

  • 检查方法有一个类型参数
  • 检查方法有一个正常的参数
  • 使用类型参数使Func<T>(与typeof(Func<>).MakeGenericType)并检查参数类型是否匹配。

LINQ很适合这种事情。完整的示例:

using System; 
using System.Reflection; 
using System.Linq; 

public class Foo 
{ 
    public void Bar<T>(Func<T> f) { } 
    public void Bar<T>(Action<T> a) { } 
} 

class Test 
{ 
    static void Main() 
    { 
     var methods = from method in typeof(Foo).GetMethods() 
         where method.Name == "Bar" 
         let typeArgs = method.GetGenericArguments() 
         where typeArgs.Length == 1 
         let parameters = method.GetParameters() 
         where parameters.Length == 1 
         where parameters[0].ParameterType == 
          typeof(Func<>).MakeGenericType(typeArgs[0]) 
         select method; 

     Console.WriteLine("Matching methods..."); 
     foreach (var method in methods) 
     { 
      Console.WriteLine(method); 
     } 
    } 
} 

基本上泛型和反射结合真是可恶,我怕:(

4

出人意料的是,它看起来像你将需要调用GetMethods()和环比的方法,直到找到你想要的

例如:

var yourMethod = typeof(Foo).GetMethods() 
    .First(m => m.Name == "Bar" 
      && m.GetParameters().Length == 1 
      && m.GetParameters()[0].ParameterType.ContainsGenericParameters 
      && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Func<>)); 
+0

它的工作原理。谢谢。 – Anne 2010-12-14 19:54:15

0

您将与刚刚只用GetMethod斗争 - 你可以尝试沿着林的东西。 es of;

var method = (from m in typeof(Foo).GetMethods() 
    where 
    m.IsGenericMethodDefinition == true && 
    m.Name == "Bar" && 
    m.GetParameters().Length > 0 && 
    m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == parameterType 
    select m).FirstOrDefault(); 
相关问题