TargetParameterCountException:discrepancia en el recuento de parámetros

TargetParameterCountException:discrepancia en el recuento de parámetros

Cuando usa la reflexión para llamar a un método, puede encontrarse con esta excepción:

Esta excepción es sencilla:no está pasando la cantidad correcta de parámetros a MethodInfo.Invoke().

Este artículo muestra tres casos diferentes en los que podría encontrarse con esta excepción al usar la reflexión.

Usando la reflexión para invocar un método

El caso más simple es cuando está invocando un método y simplemente no pasa todos los parámetros. La definición del método puede haber cambiado, o simplemente omitió uno de los parámetros. Este error es fácil de cometer, ya que el compilador no te ayuda a detectarlo.

Supongamos que tiene el siguiente método que devuelve la suma de dos números enteros:

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

El siguiente código usa la reflexión para llamar a este método:

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)

El método Util.Add() tiene dos parámetros:a y b. Este código solo pasa uno de los parámetros, a, por lo que arroja TargetParameterCountException.

La solución es simple, pase todos los parámetros. En este caso, simplemente necesitamos pasar 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)

Uso de la reflexión para invocar un método con parámetros predeterminados

Los parámetros predeterminados no funcionan igual con la reflexión. Cuando tiene un método con parámetros predeterminados e intenta llamarlo con reflexión, debe pasar todos los parámetros, predeterminados o no.

El siguiente código resta dos enteros y devuelve la diferencia. Tiene un parámetro predeterminado:b.

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

El siguiente código usa la reflexión para llamar a este método. Solo está pasando uno de los parámetros.

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() espera dos parámetros:a y b. Solo se pasa un parámetro, a, por lo que esto arroja TargetParameterCountException.

Pero espera, ¿no tiene esto un parámetro predeterminado? Sí, pero los parámetros predeterminados básicamente no funcionan con la reflexión. Debe pasar todos los parámetros, incluso si es un parámetro predeterminado.

La solución es simple, pase ambos parámetros:

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)

Uso de la reflexión para invocar un método de extensión

Los métodos de extensión son solo métodos estáticos. El método se define en una clase estática y se invoca en otro tipo. Como habrás adivinado, cuando llamas al método de extensión con reflexión, tienes que hacerlo de forma diferente a como lo harías normalmente.

Digamos que tiene el siguiente método de extensión:

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

Sin reflexionar, lo llamarías así:

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

Con reflexión, lo llamarías así:

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)

Primero, cuando usa la reflexión para llamar a un método estático, el primer parámetro de Invoke() es nulo, porque no lo está llamando en una instancia.

En segundo lugar, como puede ver en la línea resaltada, debe pasar todos los parámetros (al igual que cuando tiene parámetros predeterminados). De lo contrario, lanzará TargetParameterCountException.