TargetParameterCountException:パラメーター数の不一致

リフレクションを使用してメソッドを呼び出す場合、次の例外が発生する可能性があります:

この例外は単純です。正しい数のパラメーターを MethodInfo.Invoke() に渡していません。

この記事では、リフレクションの使用時にこの例外に遭遇する可能性のある 3 つの異なるケースを示します。

リフレクションを使用してメソッドを呼び出す

最も単純なケースは、メソッドを呼び出していて、単純にすべてのパラメーターを渡していない場合です。メソッド定義が変更されたか、単にパラメータの 1 つが省略されている可能性があります。この間違いは、コンパイラでは見つけられないため、簡単に犯してしまいます。

2 つの整数の合計を返す次のメソッドがあるとします:

public class Util
{
	public int Add(int a, int b)
	{
		return a + b;
	}
}
Code language: C# (cs)

次のコードは、リフレクションを使用してこのメ​​ソッドを呼び出します:

Util util = new Util();
int a = 1;
int b = 2;

var method = util.GetType().GetMethod("Add");
var parameters = new object[] { a };

var sum = method.Invoke(util, parameters);
Code language: C# (cs)

Util.Add() メソッドには、a と b の 2 つのパラメーターがあります。このコードはパラメーターの 1 つ (a) のみを渡しているため、TargetParameterCountException がスローされます。

解決策は簡単です。すべてのパラメーターを渡します。この場合、単純に b を渡す必要があります。

Util util = new Util();
int a = 1;
int b = 2;

var method = util.GetType().GetMethod("Add");
var parameters = new object[] { a, b };

var sum = method.Invoke(util, parameters);
Code language: C# (cs)

リフレクションを使用してデフォルト パラメータでメソッドを呼び出す

デフォルトのパラメーターは、リフレクションと同じようには機能しません。デフォルト パラメーターを持つメソッドがあり、リフレクションでそれを呼び出そうとする場合、デフォルトかどうかにかかわらず、すべてのパラメーターを渡す必要があります。

次のコードは、2 つの整数を減算し、差を返します。デフォルトのパラメーター b があります。

public class Util
{
	public int Subtract(int a, int b = 0)
	{
		return a - b;
	}
}
Code language: C# (cs)

次のコードは、リフレクションを使用してこのメ​​ソッドを呼び出します。パラメータの 1 つだけを渡しています。

Util util = new Util();
int a = 1;
int b = 2;

var method = util.GetType().GetMethod("Subtract");
var parameters = new object[] { a };

var difference = method.Invoke(util, parameters);
Code language: C# (cs)

Util.Subtract() には、a と b の 2 つのパラメーターが必要です。渡されるパラメーターは 1 つだけです – a – そのため、これが TargetParameterCountException をスローする理由です。

でも待ってください、これにはデフォルトのパラメータがありませんか?はい。ただし、デフォルトのパラメータは基本的にリフレクションでは機能しません。デフォルトのパラメータであっても、すべてのパラメータを渡す必要があります。

解決策は簡単です。両方のパラメータを渡します:

Util util = new Util();
int a = 1;
int b = 2;

var method = util.GetType().GetMethod("Subtract");
var parameters = new object[] { a, b };

var difference = method.Invoke(util, parameters);
Code language: C# (cs)

リフレクションを使用して拡張メソッドを呼び出す

拡張メソッドは単なる静的メソッドです。メソッドは 1 つの静的クラスで定義され、別の型で呼び出されます。ご想像のとおり、リフレクションで拡張メソッドを呼び出すときは、通常とは異なる方法で行う必要があります。

次の拡張メソッドがあるとします:

public static class Util
{
	public static int Multiply(this int a, int b)
	{
		return a * b;
	}
}
Code language: C# (cs)

リフレクションがなければ、次のように呼び出します:

a.Multiply(b);
Code language: C# (cs)

リフレクションを使用すると、次のように呼び出すことができます:

int a = 6;
int b = 3;

var method = typeof(Util).GetMethod("Multiply", BindingFlags.Static | BindingFlags.Public);
var parameters = new object[] { a, b };

var product = method.Invoke(null, parameters);
Code language: C# (cs)

まず、リフレクションを使用して静的メソッドを呼び出す場合、Invoke() の最初のパラメーターは null です。これは、インスタンスで呼び出していないためです。

次に、強調表示された行でわかるように、すべてのパラメーターを渡す必要があります (既定のパラメーターがある場合と同様)。それ以外の場合は、TargetParameterCountException がスローされます。