ジェネリック型のメソッドやジェネリックメソッドを呼び出す場合、引数リストの型はすべて具体的な型に型付けされている必要があります。 型付けされていない状態で呼び出した場合、例外InvalidOperationExceptionがスローされます。 そのため、引数リストにジェネリック型の型パラメータおよびジェネリックメソッドの型パラメータを含む場合は、呼び出す時点で何らかの具体的な型に型付け(置き換え)されている必要があります。
ジェネリック型(Type)ではType.MakeGenericTypeメソッド(関連:§.ジェネリック型の型情報)、ジェネリックメソッド(MethodInfo)ではMethodInfo.MakeGenericMethodメソッドを呼び出すことによって、型パラメータを具体的な型に置き換え、構築された(型付けされた)ジェネリック型・ジェネリックメソッドを取得することができます。
すべての型パラメータが具体的な型に型付けされた状態のMethodInfoでは、通常のMethodInfoと同様にInvokeメソッドで呼び出すことができます。
using System;
using System.Reflection;
// 型パラメータTCを取るジェネリック型
class C<TC> {
// ジェネリック型の型パラメータTCを引数にとるメソッド
public void M(TC tc) => Console.WriteLine($"M({typeof(TC)} = {tc})");
// ジェネリック型の型パラメータTCと、メソッドの型パラメータTMを引数にとるジェネリックメソッド
public void M<TM>(TC tc, TM tm) => Console.WriteLine($"M({typeof(TC)} = {tc}, {typeof(TM)} = {tm})");
}
class Sample {
static void Main()
{
// ジェネリック型定義(C<>)の型情報ではインスタンス作成・メソッド呼び出しはできない
// MakeGenericTypeメソッドで具体的な型(C<string>など)に型付けする必要がある
var t = typeof(C<>).MakeGenericType(typeof(string));
//var t = typeof(C<string>); // あるいは型付けされた状態の型情報を取得する
var inst = Activator.CreateInstance(t);
// 引数リストが(TC)のメソッドMを取得する
var m1 = t.GetMethod("M", types: new[] {
typeof(string) // 型パラメータTCはMakeGenericTypeでstringに型付けされている
});
// メソッドC<string>.M(string)を呼び出す
m1.Invoke(inst, new object[] {"arg"});
// 引数リストが(TC, TM)のメソッドMを取得する
var m2 = t.GetMethod("M",
genericParameterCount: 1, // 型パラメータが1つのジェネリックメソッド
types: new[] {
typeof(string), // 型パラメータTCはMakeGenericTypeでstringに型付けされている
Type.MakeGenericMethodParameter(0) // 型パラメータTMに対応する、ジェネリックメソッドの0番目の型パラメータを表すTypeを指定
}
);
// MakeGenericMethodを呼び出して、型付けされた状態のMethodInfoを作成する
var m2g = m2.MakeGenericMethod(
typeof(int) // 上記の0番目の型パラメータ(TM)を、intに型付けする
);
// メソッドC<string>.M<int>(string, int)を呼び出す
m2g.Invoke(inst, new object[] {"arg", 42});
}
}
M(System.String = arg) M(System.String = arg, System.Int32 = 42)
Type.InvokeMemberメソッドを使った呼び出しでは、具体的な型に型付けされないジェネリックメソッドを呼び出すと、例外MissingMethodExceptionがスローされます。
すべての型パラメータが型付けされているジェネリック型(ContainsGenericParametersプロパティがfalseのType)における、非ジェネリックなメソッド(型パラメータを取らないメソッド)は、通常のメソッドと同様に呼び出すことができます。