いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

ジェネリックメソッドをリフレクションで取得する方法 (System.Reflection, MethodInfo, MakeGenericMethod, IsGenericMethod, IsGenericMethodDefinition)


ジェネリックメソッドをリフレクションにて取得する際に、注意点があります。

対象となるメソッドが、ジェネリックメソッド一つの場合はGetMethod一発で取得できるが
同名のオーバーロードメソッドが複数存在する場合は、一旦メソッド一覧を取得して見つける作業が
必要となる。


基本的には、メソッド情報を取得して、MakeGenericMethodすると事足ります。
たとえば、以下の一つだけのメソッド定義がある場合、

        protected void SetPropertyValue<T>(string propName, ref T refVal, T val){
            //
            // nop.
            //
        }

以下のやり方で取得できます。

            // ジェネリック定義されている状態のメソッド情報を取得.
            MethodInfo mi = type.GetMethod("SetPropertyValue", flags);
            // 型引数を設定して、実メソッド情報を取得
            MethodInfo genericMi = mi.MakeGenericMethod(new Type[]{ typeof(DateTime) });


でも、以下のように複数の同名メソッドが存在する場合

        protected void SetPropertyValue(string propName, ref int refVal, int val){
            //
            // nop.
            //
        }

        protected void SetPropertyValue<T>(string propName, ref T refVal, T val){
            //
            // nop.
            //
        }

そのまま最初のやり方で取得すると例外が発生します。
取得するには、一旦GetMethodsにて一覧を取得し、その中から該当するメソッド情報を見つける作業が必要となります。


以下、サンプルです。

#region Genericなメソッドをリフレクションで取得

    public class GenericMethodReflectionSample : IExecutable{

        public void Execute(){
            Type         type  = typeof(GenericMethodReflectionSample);
            BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Instance);

            //
            // ジェネリックメソッドが一つしかない場合は以下のようにして取得できる。
            // 
            // ジェネリック定義されている状態のメソッド情報を取得.
            // MethodInfo mi = type.GetMethod("SetPropertyValue", flags);
            // 型引数を設定して、実メソッド情報を取得
            // MethodInfo genericMi = mi.MakeGenericMethod(new Type[]{ typeof(DateTime) });
            //
            // しかし、同名メソッドのオーバーロードが複数存在する場合は一旦GetMethodsにて
            // ループさせ、該当するメソッドを見つける作業が必要となる。
            //
            // [参照URL]
            // http://www.codeproject.com/KB/dotnet/InvokeGenericMethods.aspx
            //
            string methodName = "SetPropertyValue";
            Type[] paramTypes = new Type[]{ typeof(string), typeof(DateTime), typeof(DateTime) };
            foreach(MethodInfo mi in type.GetMethods(flags)){

                if(mi.IsGenericMethod && mi.IsGenericMethodDefinition && mi.ContainsGenericParameters){
                    if(mi.Name == methodName && mi.GetParameters().Length == paramTypes.Length){
                        MethodInfo genericMi = mi.MakeGenericMethod(new Type[]{ typeof(DateTime) } );
                        Console.WriteLine(genericMi);
                    }
                }
            }
        }

        protected void SetPropertyValue(string propName, ref int refVal, int val){
            //
            // nop.
            //
        }

        protected void SetPropertyValue<T>(string propName, ref T refVal, T val){
            //
            // nop.
            //
        }
    }
#endregion