3

私が持っている質問はこれです:インターフェイスタイプから取得されたメソッドの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呼び出しがあります。コメント。この部分は私が助けを必要としているものです。ここで指定する必要があるもの(そして私は多くのテストを行ったため、別の方法になります)、またはこのコードを置き換える必要があるもののいずれかです。

インターフェイスからメソッドの明示的な実装を使用したため、メソッドの実際の名前は「テスト」だけではありません。クラスタイプの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オブジェクトを指していません。

ポインタはありますか?

4

2 に答える 2

10

将来の参考のために、そして他の人が興味を持っている場合、ここで@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;
        }
    }
}
于 2009-10-06T12:15:59.150 に答える
5

を見てくださいType.GetInterfaceMap。申し訳ありませんが、急いでいるので、完全な答えを出す時間はありませんが、それは始まりになるはずです。

于 2009-10-06T11:56:10.973 に答える