2012-10-28 49 views
9

假設我有一個類,像這樣:如何從封閉式的MethodInfo獲取MethodInfo的開放泛型類型

public class MyClass<T> 
{ 
    public void Foo(T t) 
    { 
    } 
} 

現在,假設,我和MyClass<int>實例其Foo方法的MethodInfo。 調用methodInfo.GetParameters()將返回帶有一個條目的ParameterInfo數組,其類型爲int。我的問題是,我似乎無法找到,如果該參數在課程中被聲明爲intT

我想達到什麼目的?
在運行時,我想從Visual Studio生成的XML Doc文件中讀取由MethodInfo指定的方法的文檔。
對於上述定義的方法中,關鍵是這樣的:

<namespace>.MyClass`1.Foo(`0) 

`0的指的是聲明類的第一個通用類型參數。爲了能夠構造這個字符串,我需要以某種方式獲得這些信息。
但是如何?MethodInfo似乎並沒有包含信息...

+0

高級反射技術通常需要回退到IMetaDataImport2。從C#中使用並不容易。 –

+0

@HansPassant:該接口是否支持我的場景? –

+0

所以如果你的方法是「public void Foo(int i,T t,string s)」,你會想得到類似於「 .MyClass'1.Foo(int,'0,string)」? – user276648

回答

3

的關鍵似乎是Type.ContainsGenericParameters參數類型:

鑑於

public class MyClass<T> 
{ 
    public void Foo(T t) 
    { 
    } 

    public void Bar(int i) 
    { 

    } 
} 

然後

class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new MyClass<int>(); 

     // Closed type 
     var closedType = obj.GetType(); 

     // Open generic (typeof(MyClass<>)) 
     var openType = closedType.GetGenericTypeDefinition(); 

     // Methods on open type 
     var fooT = openType.GetMethod("Foo"); 
     var barint = openType.GetMethod("Bar"); 

     // Parameter types 
     var tInFoo = fooT.GetParameters()[0].ParameterType; 
     var iInBar = barint.GetParameters()[0].ParameterType; 

     // Are they generic? 
     var tInFooIsGeneric = tInFoo.ContainsGenericParameters; 
     var iInBarIsGeneric = iInBar.ContainsGenericParameters; 

     Console.WriteLine(tInFooIsGeneric); 
     Console.WriteLine(iInBarIsGeneric); 

     Console.ReadKey(); 
    } 
} 

輸出

True 
False 

這顯然需要重載,多做事等等。

+0

啊哈!這看起來不錯。稍後會詳細檢查。謝謝! –

+0

對不起,接受這麼長時間來接受你的答案。它是現貨。 –

+1

如果我有'Foo'方法的重載,我怎麼才能得到正確的'MethodInfo'? 'GetMethod'引發'AmbiguousMatchException'。 'GetMethod'需要接收參數類型,但我無法從'MethodInfo'關閉類型 –

1

你能否通過Type.GetGenericTypeDefinition Method得到泛型類的定義,並且在那裏的定義相同的方法,比如,通過名稱(簽字),然後比較Foo(T t)Foo(int t)

MyClass<int> c = new MyClass<int>(); 

Type concreteType = c.GetType(); 
Console.Write("Concrete type name:"); 
Console.WriteLine(concreteType.FullName); 
Console.WriteLine(); 

MethodInfo concreteMethod = concreteType.GetMethod("Foo"); 
if (concreteMethod != null) 
{ 
    Console.WriteLine(concreteMethod.Name); 
    foreach (ParameterInfo pinfo in concreteMethod.GetParameters()) 
    { 
     Console.WriteLine(pinfo.Name); 
     Console.WriteLine(pinfo.ParameterType); 
     Console.WriteLine(); 
    } 
    Console.WriteLine(); 
} 

if (concreteType.IsGenericType) 
{ 
    Console.Write("Generic type name:"); 
    Type genericType = concreteType.GetGenericTypeDefinition(); 
    Console.WriteLine(genericType.FullName); 
    Console.WriteLine(); 

    MethodInfo genericMethod = genericType.GetMethod("Foo"); 
    if (genericMethod != null) 
    { 
     Console.WriteLine(genericMethod.Name); 
     foreach (ParameterInfo pinfo in genericMethod.GetParameters()) 
     { 
      Console.WriteLine(pinfo.Name); 
      Console.WriteLine(pinfo.ParameterType); 
      Console.WriteLine(); 
     } 
     Console.WriteLine(); 
    } 
} 
+0

我也考慮過這個問題,但我不太確定那些重載方法會如何工作。 –

+0

@DanielHilgarth,同意尋找相應方法的重載可能是一件棘手的事情。但是我也沒有看到其他的出路。 – horgh

1

我不知道你有沒有使用Mono.Cecil能代替的。NET的反射考慮。

// Gets the AssemblyDefinition (similar to .Net's Assembly). 
Type testType = typeof(MyClass<>); 
AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(new Uri(testType.Assembly.CodeBase).LocalPath); 
// Gets the TypeDefinition (similar to .Net's Type). 
TypeDefinition classDef = assemblyDef.MainModule.Types.Single(typeDef => typeDef.Name == testType.Name); 
// Gets the MethodDefinition (similar to .Net's MethodInfo). 
MethodDefinition myMethodDef = classDef.Methods.Single(methDef => methDef.Name == "Foo"); 

然後myMethodDef.FullName回報

"System.Void MyNamespace.MyClass`1::Foo(System.Int32,T,System.String)" 

classDef.GenericParameters[0].FullName回報

"T" 

注意Mono.Cecil能使用泛型編寫,嵌套類和陣列的不同方式:

List[T] => List<T> 
MyClass+MyNestedClass => MyClass/MyNestedClass 
int[,] => int[0...,0...] 
+0

問題是我已經有一個MethodInfo對象,我需要檢索該信息。 –

相關問題