TargetParameterCountException:mancata corrispondenza del conteggio dei parametri

TargetParameterCountException:mancata corrispondenza del conteggio dei parametri

Quando si utilizza la riflessione per chiamare un metodo, è possibile che si verifichi questa eccezione:

Questa eccezione è semplice:non stai passando il numero corretto di parametri a MethodInfo.Invoke().

Questo articolo mostra tre diversi casi in cui potresti imbatterti in questa eccezione quando usi la riflessione.

Utilizzare la riflessione per invocare un metodo

Il caso più semplice è quando si invoca un metodo e semplicemente non si passano tutti i parametri. La definizione del metodo potrebbe essere cambiata o hai semplicemente omesso uno dei parametri. Questo errore è facile da fare, dal momento che il compilatore non ti aiuta a prenderlo.

Supponiamo che tu abbia il seguente metodo che restituisce la somma di due numeri interi:

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

Il codice seguente usa la riflessione per chiamare questo metodo:

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)

Il metodo Util.Add() ha due parametri:a e b. Questo codice sta solo passando uno dei parametri - a - quindi perché sta generando TargetParameterCountException.

La soluzione è semplice, passa tutti i parametri. In questo caso, dobbiamo semplicemente passare in 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)

Utilizzare la riflessione per invocare un metodo con parametri predefiniti

I parametri predefiniti non funzionano allo stesso modo con la riflessione. Quando hai un metodo con parametri predefiniti e provi a chiamarlo con la riflessione, devi passare tutti i parametri, predefiniti o meno.

Il codice seguente sottrae due numeri interi e restituisce la differenza. Ha un parametro predefinito – b.

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

Il codice seguente usa la riflessione per chiamare questo metodo. Sta solo passando uno dei parametri.

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() prevede due parametri:a e b. Viene passato solo un parametro – a – quindi perché questo sta lanciando TargetParameterCountException.

Ma aspetta, questo non ha un parametro predefinito? Sì, ma i parametri predefiniti fondamentalmente non funzionano con la riflessione. Devi passare tutti i parametri, anche se è un parametro predefinito.

La soluzione è semplice, passa entrambi i parametri:

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)

Utilizzare la riflessione per invocare un metodo di estensione

I metodi di estensione sono solo metodi statici. Il metodo è definito in una classe statica e chiamato su un altro tipo. Come avrai intuito, quando chiami il metodo di estensione con riflessione, devi farlo in modo diverso da come faresti normalmente.

Supponiamo che tu abbia il seguente metodo di estensione:

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

Senza riflettere, lo chiamereste così:

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

Con la riflessione, la chiamereste così:

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)

Innanzitutto, quando usi la riflessione per chiamare un metodo statico, il primo parametro di Invoke() è null, perché non lo stai chiamando su un'istanza.

In secondo luogo, come puoi vedere sulla riga evidenziata, devi passare tutti i parametri (proprio come quando hai i parametri predefiniti). Altrimenti genererà TargetParameterCountException.