Преобразовать объект MethodInfo, полученный из типа интерфейса, в соответствующий объект MethodInfo в реализующем типе в C#?
У меня есть вопрос: если у меня есть метод MethodInfo для метода, полученного из типа интерфейса, и у меня также есть объект Type для класса, который реализует этот интерфейс, но он реализует указанный метод с явной реализацией, Как правильно получить соответствующий объект MethodInfo для реализации метода в этом классе?
Причина, по которой мне нужно это сделать, заключается в том, что к реализующим методам могут быть применены некоторые атрибуты, и мне нужно найти их с помощью отражения, но у класса, которому нужно найти эти атрибуты, есть только ссылка на объект для реализующего класса и тип. объект (+ соответствующие объекты 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
ясно, что имя имеет полное имя интерфейса и пространство имен перед ним. Однако из-за перегрузки мне кажется, что мне нужно найти все такие методы реализации в классе (т. Е. Предположить, что существует несколько методов Test, различающихся по параметрам), а затем сравнить параметры.
Есть ли более простой способ? По сути, я бы хотел, как только у меня будет объект 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 из интерфейса.
Есть указатели?
2 ответа
Смотреть на Type.GetInterfaceMap
, Извините - я спешу, поэтому у меня нет времени на полный ответ, но это должно быть началом.
Для дальнейшего использования и, если кому-то интересно, решение, данное мне Greg Beech здесь, заключалось в использовании 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;
}
}
}