2016-09-22 26 views
0

我有一個類與幾個泛型重載的方法。我試圖通過它的參數類型來獲取特定的一個。當我堅持前兩個時(使用int和string類型的參數),做起來相對容易。但是不管我做什麼,我都無法讓我的程序注意到第三個,用於通用列表。我使用錯誤的Type參數嗎?如果是的話,什麼是正確的方式?C#:GetMethod的類型(通用列表)

/* rest of code */ 
    static void Main(string[] args) { 
     MethodInfo method = 
      typeof(c).GetMethod("m", new Type[] { typeof(int) }); 

     Console.WriteLine(method); 

     method = 
      typeof(c).GetMethod("m", new Type[] { typeof(String) }); 

     Console.WriteLine(method); 

     method = 
      typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) }); 

     Console.WriteLine(method); 

     Console.ReadKey(); 
    } 
} 

static class c 
{ 
    public static void m<T>(int i) 
    { 
    } 

    public static void m<T>(String s) 
    { 
    } 

    public static void m<T>(IEnumerable<T> Ls) 
    { 
    } 
} 
+0

可能的重複[如何使用反射來調用泛型方法?](http://stackoverflow.com/questions/232535/how-do-i-use-reflection-to -call-a-generic-method) – CSharpie

+0

@CSharpie我認爲這個問題更多的是關於如何獲得泛型方法本身,而你引用的問題的答案並沒有真正解決這個問題。 – strongbutgood

回答

1

短版:typeof(IEnumerable<>)是不一樣的typeof(IEnumerable<T>)(對於某些T)。

更長的版本:沒有方法void c.m(IEnumerable<> Ls),只有重載的地方泛型參數將是一些特定的 - 在運行時存在的類型 - 由於某些代碼引用該泛型方法的實例化需要抖動創建該方法的類型。

在您的測試代碼中添加一個通用方法的某個實例的調用,然後爲該實例執行GetMethod

考慮以下幾點:

using System.Collections.Generic; 
using System.Linq; 
using static System.Console; 

class Methods { 
    public static void M(int x)  { 
     // no-op 
    } 

    public static void M<T>(IEnumerable<T> x)  { 
     // no-op 
    } 
} 

class Program { 
    static void Main(string[] args) { 
     Methods.M(0); 
     Methods.M(new[] { "a", "b" }); 

     ShowAllM(); 
    } 

    public static void ShowAllM() { 
     var tm = typeof(Methods); 
     foreach (var mi in tm.GetMethods().Where(m => m.Name == "M")) 
     { 
      WriteLine(mi.Name); 
      foreach (var p in mi.GetParameters()) 
      { 
       WriteLine($"\t{p.ParameterType.Name}"); 
      } 
     } 
    } 
} 

產生的輸出:

 
M 
    Int32 
M 
    IEnumerable`1 

注有從一般過載只有一個結果。如果​​的呼叫被添加到Main那麼輸出是相同的

對於反射只有一種方法,它的論點是否反映了它的「開放泛型」性質,但這與用開放泛型類型(例如IEnumerable<>)可調用不同,因爲開放類型不可實例化。

(我捏造許多這裏的技術細節。這是instruictive看在typeof(IEnumerable<>)typeof(IEnumerable<int>)之間的調試器的區別。)

+0

是否可以添加代碼示例?我不認爲我明白你的意思_GetMethod該實例_。 – Daedan

1

第三種方法具有m<T>(IEnumerable<T>)的簽名,但你的例子顯示了一個試圖找到一個簽名爲m(IEnumerable<>)的方法。

typeof(IEnumerable<T>)typeof(IEnumerable<>)之間的區別是前者是一個泛型類型,第二個是泛型類型定義,這些不是一回事。泛型類型由泛型類型定義和泛型類型參數確定。

考慮到這一點,你可能需要使用:

method = 
     typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) }); 

和替代的枚舉,你將通過到方法的類型。

在另一方面,如果你不知道前面,你可以得到的泛型方法定義的枚舉類型,使可用通用的方法,當你需要它:

methodDef = 
     typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition(); 
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) }); 
+0

而且可以在不改變任何有關該方法的情況下獲得它?目前我正在使用外部庫,所以更改不是真正的選擇。我知道我能獲得通過的getMethods(相關的MethodInfo)並搜索它是正確的,但它是如此_crude_ – Daedan

+0

@Daedan是,該方法是好的,因爲它是和我的例子應該努力獲得的MethodInfo,您可以使用通過假設這就是你想要做的事情來進行調用。一旦擁有它,你如何使用MethodInfo? – strongbutgood

+0

我沒有它'方法= typeof運算(c)中.GetMethod( 「M」,新類型[] {typeof運算(IEnumerable的)});'返回null。爲了得到MethodInfo,我必須修改我的方法,從specyfically以IEnumerable 作爲參數 – Daedan

0

如果您刪除通用defenitions從int和字符串的方法:

public static void m(int i) 
    { 
    } 

    public static void m(String s) 
    { 
    } 

    public static void m<T>(IEnumerable<T> Ls) 
    { 
    } 

而使用以下行獲得所需的通用方法:

method = typeof(c).GetMethods().FirstOrDefault(m => m.IsGenericMethod && 
        m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() 
         == typeof(IEnumerable<>)); 

這將做詭計