1. ホーム
  2. c#

[解決済み] リフレクションによる拡張手法の特定

2023-08-30 15:21:14

質問

C#において、あるメソッドが拡張メソッドとしてクラスに追加されたかどうかを判断するために、リフレクションを使用するテクニックはありますか?

以下のような拡張メソッドがある場合、Reverse()がstringクラスに追加されたことを判断することは可能でしょうか?

public static class StringExtensions
{
    public static string Reverse(this string value)
    {
        char[] cArray = value.ToCharArray();
        Array.Reverse(cArray);
        return new string(cArray);
    }
}

拡張メソッドが開発者によって適切に追加されたことを単体テストで判断するための仕組みを探しています。 これを試みる理由の一つは、開発者によって実際のクラスに同様のメソッドが追加される可能性があり、もしそうであれば、コンパイラはそのメソッドをピックアップすることでしょう。

どのように解決するのか?

拡張メソッドが定義されている可能性のあるすべてのアセンブリを確認する必要があります。

で装飾されたクラスを探します。 ExtensionAttribute で装飾されたクラス、そしてそのクラス内のメソッドで で装飾された ExtensionAttribute . そして、最初のパラメーターの型をチェックして、興味のある型にマッチするかどうかを確認します。

これが完全なコードです。より厳密であるべきですが(型がネストされていないことや、少なくとも1つのパラメータがあることをチェックしていません)、これはあなたの手助けになるはずです。

using System;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;

public static class FirstExtensions
{
    public static void Foo(this string x) {}
    public static void Bar(string x) {} // Not an ext. method
    public static void Baz(this int x) {} // Not on string
}

public static class SecondExtensions
{
    public static void Quux(this string x) {}
}

public class Test
{
    static void Main()
    {
        Assembly thisAssembly = typeof(Test).Assembly;
        foreach (MethodInfo method in GetExtensionMethods(thisAssembly,
            typeof(string)))
        {
            Console.WriteLine(method);
        }
    }

    static IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly,
        Type extendedType)
    {
        var query = from type in assembly.GetTypes()
                    where type.IsSealed && !type.IsGenericType && !type.IsNested
                    from method in type.GetMethods(BindingFlags.Static
                        | BindingFlags.Public | BindingFlags.NonPublic)
                    where method.IsDefined(typeof(ExtensionAttribute), false)
                    where method.GetParameters()[0].ParameterType == extendedType
                    select method;
        return query;
    }
}