2009-10-06 43 views
3

我有這樣的問題:如果我有MethodInfo對象,對於從接口類型獲得的方法,我也有一個實現此接口的類的Type對象,但它實現了具有顯式實現,我該如何正確獲取該類中實現方法的相應MethodInfo對象?將從接口類型獲取的MethodInfo對象轉換爲C#中實現類型的相應MethodInfo對象?

我需要這樣做的原因是實現方法可以有一些屬性應用於它們,我需要通過反射來找到這些屬性,但需要查找這些屬性的類只有實現類的對象引用,以及接口的Type對象(+對應的MethodInfo對象)。

所以,讓我們假設我有以下程序:

using System; 
using System.Reflection; 

namespace ConsoleApplication8 
{ 
    public interface ITest 
    { 
     void Test(); 
    } 

    public class Test : ITest 
    { 
     void ITest.Test() 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Type interfaceType = typeof(ITest); 
      Type classType = typeof(Test); 

      MethodInfo testMethodViaInterface = 
       interfaceType.GetMethods()[0]; 
      MethodInfo implementingMethod = 
       classType.GetMethod(/* ??? */"Test"); 

      Console.Out.WriteLine("interface: " + 
       testMethodViaInterface.Name); 
      if (implementingMethod != null) 
       Console.Out.WriteLine("class: " + 
        implementingMethod.Name); 
      else 
       Console.Out.WriteLine("class: unable to locate"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 
} 

運行這給了我:

interface: Test 
class: unable to locate 
Press enter to exit... 

最多的代碼中有一個.GetMethod通話用???評論。這部分是我需要幫助的。無論我需要在這裏指定(和我已經測試了很多,這使我以另一種方式)或我需要替換此代碼。

因爲我從界面使用了顯式的方法實現,所以方法的實際名稱不僅僅是「Test」。如果我傾倒的getMethods)的全部內容(類類型的數組,使用此代碼:

foreach (var mi in classType.GetMethods(
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) 
{ 
    Console.Out.WriteLine(mi.Name); 
} 

然後我得到這樣的:

ConsoleApplication8.ITest.Test   <-- this is the one I want 
ToString 
Equals 
GetHashCode 
GetType 
Finalize 
MemberwiseClone 

顯然,這個名字具有的全名接口及其前面的名稱空間。但是,由於重載,看起來像我必須做的是在類中找到所有這些實現方法(即假設有多個測試方法隨參數而變化),然後比較參數。

有沒有更簡單的方法?基本上我想,一旦我從接口獲得MethodInfo對象的方法,就可以通過獲取它的MethodInfo對象來找到實現此方法的類的確切方法。

請注意,在這裏我處於一種糟糕的情況,所以如果我必須循環遍歷類中的方法以從界面中找到確切的方法,那沒關係,只要我有一個很好的方法來確定何時我找到了正確的。

我試圖改變上述這樣的循環:

foreach (var mi in classType.GetMethods(
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) 
{ 
    if (mi.GetBaseDefinition() == testMethodViaInterface) 
     Console.Out.WriteLine(mi.Name); 
} 

這並沒有打印出任何東西,所以這樣的方法顯然GetBaseDefinition不指向從接口的MethodInfo對象。

任何指針?

+0

有一個很好的解決這個問題就在這裏: http://stackoverflow.com/questions/1113635/how-to-get-methodinfo-of-interface-method-having-implementing-methodinfo -of-cla – gillyb 2013-01-31 08:36:09

回答

5

Type.GetInterfaceMap。對不起 - 我很忙,所以沒有時間做完整的答案,但它應該是一個開始。

+0

好吧,讓我這樣做。 – 2009-10-06 11:57:05

+0

哦,這正是我所需要的,想要在它上面構建一個擴展方法以便輕鬆查詢,但是那個點擊! – 2009-10-06 11:58:09

+0

我會用擴展方法和編輯後的代碼發佈自己的答案。 – 2009-10-06 12:01:26

10

爲了將來的參考,如果其他人有興趣,@Greg Beechhere給我的解決方案是使用Type.GetInterfaceMap

下面是改變後的程序代碼,底部有擴展方法。

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

namespace ConsoleApplication8 
{ 
    public interface ITest 
    { 
     void Test(); 
    } 

    public class Test : ITest 
    { 
     void ITest.Test() 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Type interfaceType = typeof(ITest); 
      Type classType = typeof(Test); 

      InterfaceMapping map = classType.GetInterfaceMap(interfaceType); 

      MethodInfo testMethodViaInterface = interfaceType.GetMethods()[0]; 
      MethodInfo implementingMethod = testMethodViaInterface.GetImplementingMethod(classType); 

      Console.Out.WriteLine("interface: " + testMethodViaInterface.Name); 
      if (implementingMethod != null) 
       Console.Out.WriteLine("class: " + implementingMethod.Name); 
      else 
       Console.Out.WriteLine("class: unable to locate"); 

      Console.Out.Write("Press enter to exit..."); 
      Console.In.ReadLine(); 
     } 
    } 

    public static class TypeExtensions 
    { 
     /// <summary> 
     /// Gets the corresponding <see cref="MethodInfo"/> object for 
     /// the method in a class that implements a specific method 
     /// from an interface. 
     /// </summary> 
     /// <param name="interfaceMethod"> 
     /// The <see cref="MethodInfo"/> for the method to locate the 
     /// implementation of.</param> 
     /// <param name="classType"> 
     /// The <see cref="Type"/> of the class to find the implementing 
     /// method for. 
     /// </param> 
     /// <returns> 
     /// The <see cref="MethodInfo"/> of the method that implements 
     /// <paramref name="interfaceMethod"/>. 
     /// </returns> 
     /// <exception cref="ArgumentNullException"> 
     /// <para><paramref name="interfaceMethod"/> is <c>null</c>.</para> 
     /// <para>- or -</para> 
     /// <para><paramref name="classType"/> is <c>null</c>.</para> 
     /// </exception> 
     /// <exception cref="ArgumentException"> 
     /// <para><paramref name="interfaceMethod"/> is not defined in an interface.</para> 
     /// </exception> 
     public static MethodInfo GetImplementingMethod(this MethodInfo interfaceMethod, Type classType) 
     { 
      #region Parameter Validation 

      if (Object.ReferenceEquals(null, interfaceMethod)) 
       throw new ArgumentNullException("interfaceMethod"); 
      if (Object.ReferenceEquals(null, classType)) 
       throw new ArgumentNullException("classType"); 
      if (!interfaceMethod.DeclaringType.IsInterface) 
       throw new ArgumentException("interfaceMethod", "interfaceMethod is not defined by an interface"); 

      #endregion 

      InterfaceMapping map = classType.GetInterfaceMap(interfaceMethod.DeclaringType); 
      MethodInfo result = null; 

      for (Int32 index = 0; index < map.InterfaceMethods.Length; index++) 
      { 
       if (map.InterfaceMethods[index] == interfaceMethod) 
        result = map.TargetMethods[index]; 
      } 

      Debug.Assert(result != null, "Unable to locate MethodInfo for implementing method"); 

      return result; 
     } 
    } 
} 
相關問題