2009-10-06 2 views
3

У меня есть вопрос: если у меня есть объект MethodInfo, для метода, полученного из типа интерфейса, и у меня также есть объект Type для класса, реализующего этот интерфейс, но он реализует указанный метод с явным Как правильно получить соответствующий объект MethodInfo для метода реализации в этом классе?Перевод объекта MethodInfo, полученного из типа интерфейса, в соответствующий объект MethodInfo по типу реализации в C#?

Причина, по которой мне нужно сделать это, заключается в том, что методы реализации могут иметь некоторые атрибуты, применяемые к ним, и мне нужно найти их через отражение, но класс, который должен найти эти атрибуты, имеет только ссылку на объект для класса реализации , и объект 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... 

Up в коде есть вызов .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

ответ

5

Посмотрите на Type.GetInterfaceMap. Извините - я в спешке, поэтому у меня нет времени на полный ответ, но это должно быть началом.

+0

Хорошо, позвольте мне сделать это. –

+0

Ох, это было именно то, что мне было нужно, хочу построить метод расширения поверх него для удобства запросов, но это попало в точку! –

+0

Я отправлю ответ самостоятельно с помощью метода расширения и отредактированного кода. –

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; 
     } 
    } 
}