简体   繁体   English

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

[英]Translating a MethodInfo object obtained from an interface type, to the corresponding MethodInfo object on an implementing type in C#?

The question I have is this: If I have the MethodInfo object, for a method, obtained from an interface type, and I also have the Type object for a class that implements this interface, but it implements the said method with an explicit implementation, how do I correctly obtain the corresponding MethodInfo object for the implementing method in that class? 我的问题是:如果我有一个MethodInfo对象,对于一个从接口类型获得的方法,我也有一个实现这个接口的类的Type对象,但是它实现了带有显式实现的所述方法,如何为该类中的实现方法正确获取相应的MethodInfo对象?

The reason I need to do this is that implementing methods can have some attributes applied to them, and I need to find these through reflection, but the class that needs to find those attributes only have an object reference for the implementing class, and the Type object (+ corresponding MethodInfo objects) for the interface. 我需要这样做的原因是实现方法可以有一些属性应用于它们,我需要通过反射找到它们,但是需要找到这些属性的类只有实现类的对象引用,以及类型对象(+对应的MethodInfo对象)用于接口。

So, let's assume I have the following program: 所以,我们假设我有以下程序:

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

Running this gives me: 运行这个给了我:

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

Up in the code there is a .GetMethod call with a ??? 在代码中有一个.GetMethod调用带??? comment. 评论。 This part is what I need help with. 这部分是我需要帮助的部分。 Either what I need to specify here (and I've tested a lot, which brings me to the other way) or what I need to replace this code with. 要么我需要在这里指定(我已经测试了很多,这会带我到另一个方向)或者我需要用什么代替这个代码。

Since I used explicit implementation of the method from the interface, the actual name of the method isn't just "Test". 由于我在界面中使用了方法的显式实现,因此方法的实际名称不仅仅是“Test”。 If I dump the entire contents of the GetMethods() array of the class type, with this code: 如果我转储类类型的GetMethods()数组的全部内容,使用以下代码:

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

then I get this: 然后我明白了:

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

clearly, the name has the full name of the interface and its namespace in front of it. 很明显,该名称具有接口的全名及其前面的命名空间。 However, due to overloading, what it looks like I have to do is find all such implementing methods in the class (ie. assuming there's multiple Test methods varying by parameters), and then compare parameters. 但是,由于重载,我要做的就是在类中找到所有这样的实现方法(即假设有多个Test方法因参数而异),然后比较参数。

Is there an easier way? 有更容易的方法吗? Basically I'd like to, once I have the MethodInfo object for a method from an interface, to find the exact method that a class that implements this method, by getting its MethodInfo object. 基本上我想,一旦我从一个接口的方法获得MethodInfo对象,就可以通过获取它的MethodInfo对象来找到实现此方法的类的确切方法。

Note that I'm in a loopy situation here, so if I have to loop through the methods in the class to find the exact method from the interface, that's ok, as long as I have a good way to identify when I have found the right one. 请注意,我在这里处于循环状态,所以如果我必须循环遍历类中的方法以从界面中找到确切的方法,那没关系,只要我有一个很好的方法来确定何时找到了正确对象,真爱。

I tried to change the loop above like this: 我试着像这样改变上面的循环:

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

This didn't print out anything, so clearly GetBaseDefinition on such a method doesn't point to the MethodInfo object from the interface. 这没有打印出任何东西,所以很明显这样的方法上的GetBaseDefinition没有从接口指向MethodInfo对象。

Any pointers? 有什么指针吗?

For future reference, and if others are interested, the solution given to me by @Greg Beech here was to use Type.GetInterfaceMap . 对于未来的参考,如果其他人有兴趣,通过给我的解决方案@格雷格榉 这里是使用Type.GetInterfaceMap

Here's the altered program code with an extension method at the bottom. 这是改变的程序代码,底部有一个扩展方法。

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

Look at Type.GetInterfaceMap . 查看Type.GetInterfaceMap Sorry - am in a rush so don't have time for a full answer but it should be a start. 对不起 - 我很急,所以没有时间做一个完整的答案,但这应该是一个开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM