2010-12-14 84 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(); 
相關問題