c# - 将从接口(interface)类型获得的 MethodInfo 对象转换为 C# 中实现类型的相应 MethodInfo 对象?

标签 c# reflection interface methodinfo

我的问题是:如果我有一个方法的 MethodInfo 对象,它是从一个接口(interface)类型获得的,我还有一个实现这个接口(interface)的类的 Type 对象,但是它用一个显式实现,如何正确获取该类中实现方法对应的MethodInfo对象?

我需要这样做的原因是实现方法可以应用一些属性,我需要通过反射找到这些,但是需要找到这些属性的类只有实现类的对象引用,和接口(interface)的 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 调用评论。这部分是我需要帮助的。我需要在此处指定的内容(并且我已经进行了很多测试,这使我转向了另一种方式)或者我需要用什么来替换此代码。

由于我使用了来自接口(interface)的方法的显式实现,所以该方法的实际名称不仅仅是“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

很明显,名称前面有接口(interface)的全名及其命名空间。然而,由于重载,看起来我必须做的是在类中找到所有这样的实现方法(即假设有多个测试方法因参数而异),然后比较参数。

有没有更简单的方法?基本上,一旦我从接口(interface)中获得某个方法的 MethodInfo 对象,我就会通过获取其 MethodInfo 对象来找到实现此方法的类的确切方法。

请注意,我在这里处于循环状态,所以如果我必须循环遍历类中的方法以从接口(interface)中找到确切的方法,那没关系,只要我有一个很好的方法来识别我何时找到了合适的。

我试着像这样改变上面的循环:

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

这并没有打印出任何东西,很明显 GetBaseDefinition 没有指向接口(interface)中的 MethodInfo 对象。

有什么建议吗?

最佳答案

为了将来引用,如果其他人有兴趣,@Greg Beech给我的解决方案here是使用 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;
        }
    }
}

关于c# - 将从接口(interface)类型获得的 MethodInfo 对象转换为 C# 中实现类型的相应 MethodInfo 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1525096/

相关文章:

c# - 与 OutputCacheAttribute 交互

c# - 使用包含变量名称的字符串访问变量

c# - 处理通用接口(interface)时的解决方法

javascript - Async/Await 在 ASP.NET Core Controller 操作中没有按预期工作

c# - 获取 ProjectItem 的命名空间

c# - 在C#中使用weka : Unable to cast object of type 'java.util.ArrayList' to type 'System.Collections.Generic.List`

C# - 如何知道对象是否是 ICollection 的衍生物

c# - C# 枚举自动翻译为 JavaScript

c# - 这是 DIP (SOLID) 的有效使用吗?

java - 文本用户界面,无法使用方法