Metodi con un numero variabile di Argomenti in C#
Numero Variabile di Argomenti (var-args)
Finora, abbiamo esaminato la dichiarazione di metodi per i quali la lista dei parametri coincide con il numero degli argomenti che passiamo a quel metodo, tramite la sua invocazione.
Ora vedremo come dichiarare metodi che permettono che il numero di argomenti sia diverso ogni volta che il metodo viene invocato, in modo da soddisfare le esigenze del codice invocante.
Tali metodi sono spesso chiamati metodi con un numero variabile di argomenti o metodi var-args.
Riprendiamo, dalle lezioni precedenti, un esempio che calcola la somma di un array contenente dei prezzi di libri da acquistare e ne calcola il totale. In quell'esempio, come parametro abbiamo passato un array di tipo decimal
che consiste nei prezzi dei libri scelti:
static void StampaCostoTotale(decimal[] prezzi)
{
decimal prezzoTotale = 0;
foreach (decimal prezzoSingolo in prezzi)
{
prezzoTotale += prezzoSingolo;
}
Console.WriteLine("L'importo totale per tutti i libri è:" + prezzoTotale);
}
Definito in questo modo, il metodo suppone che, sempre prima della sua invocazione, sia stato creato un array con numeri di tipo decimal
ed essi siano stati inizializzati con determinati valori.
Nel nostro caso con i libri, dobbiamo creare un nuovo array, appositamente per quell'invocazione del metodo:
decimal[] prezzi = new decimal[] { 3m, 2.5m };
StampaCostoTotale(prezzi);
Tuttavia, modificando la dichiarazione del metodo (come vedremo tra poco), saremo in grado di passare direttamente la lista con i prezzi dei libri, come argomenti del metodo:
StampaCostoTotale(3m, 2.5m);
StampaCostoTotale(3m, 5.1m, 10m, 4.5m);
Tale invocazione è possibile solo se abbiamo dichiarato il metodo in modo che accetti un numero variabile di argomenti (var-args).
Infatti, un metodo che accetta un numero variabile di argomenti può essere invocato con un numero diverso di argomenti, ogni volta che viene chiamato. Il vincolo è che il tipo di tutti gli argomenti passati deve essere lo stesso.
Come Dichiarare un Metodo con Numero Variabile di Argomenti
Formalmente la dichiarazione di un metodo con numero variabile di argomenti è la stessa della dichiarazione di qualsiasi altro metodo:
static tipo_ritorno nome_metodo(lista_parametri)
{
// Corpo del metodo
}
La differenza è che la lista_parametri
è dichiarata con la parola chiave params
nel modo mostrato di seguito:
tipo_1 nome_1, tipo_2 nome_2, ..., params tipo[] nome_n
L'ultimo elemento della dichiarazione della lista, dichiarato con la parola chiave params
, è quello che permette il passaggio di un numero casuale di argomenti di tipo tipo
, per ogni invocazione del metodo.
Nella dichiarazione di quell'elemento, prima del suo tipo tipo
dobbiamo aggiungere params
:
params tipo[] nome_n
Il tipo tipo
può essere sia primitivo che per riferimento.
Le regole e le caratteristiche speciali per gli altri elementi della lista dei parametri del metodo, che precedono il parametro var-args nome
, sono le stesse, come quelle discusse nella lezione precedente.
Per chiarire quanto spiegato finora, discuteremo un esempio di dichiarazione e invocazione di un metodo con numero variabile di argomenti:
static long CalcolaSomma(params int[] elementi)
{
long somma = 0;
foreach (int elemento in elementi)
{
somma += elemento;
}
return somma;
}
static void Main()
{
long somma1 = CalcolaSomma(2, 5);
Console.WriteLine(somma1);
long somma2 = CalcolaSomma(4, 0, -2, 12);
Console.WriteLine(somma2);
long somma3 = CalcolaSomma();
Console.WriteLine(somma3);
}
L'esempio somma i numeri nonostante il loro numero non è noto in anticipo. Il metodo può essere invocato con uno, due o più parametri, così come senza parametri.
Se eseguiamo l'esempio otterremo il seguente risultato:
7
14
0
Array vs params
Dalla definizione formale, data sopra, del parametro che permette il passaggio di un numero variabile di argomenti tramite l'invocazione del metodo, vediamo che esso è in realtà un nome di un array.
Prendiamo la dichiarazione di CalcolaSomma
:
static long CalcolaSomma(params int[] elementi)
Il parametro elementi
è a tutti gli effetti un array di int
.
Tramite l'invocazione del metodo, gli argomenti di tipo int
o tipo compatibile che passiamo al metodo (senza preoccuparci del loro numero) saranno conservati in questo array.
Poi saranno usati nel corpo del metodo. L'accesso e la gestione di questi parametri funziona nello stesso modo in cui lavoriamo con gli array.
Per renderlo più chiaro modificheremo il metodo che calcola la somma dei prezzi dei libri scelti, per ottenere un numero variabile di argomenti:
static void StampaCostoTotale(params decimal[] prezzi)
{
decimal prezzoTotale = 0;
foreach (decimal prezzoSingolo in prezzi)
{
prezzoTotale += prezzoSingolo;
}
Console.WriteLine("L'importo totale di tutti i libri è: " + prezzoTotale);
}
Come possiamo vedere l'unico cambiamento è aggiungere params
prima di decimal[]
. Nel corpo del nostro metodo, prezzi
è ancora un array di tipo decimal
, quindi lo usiamo nello stesso modo di prima.
Ora possiamo invocare il nostro metodo, senza bisogno di dichiarare in anticipo un array di numeri e passarlo come argomento:
static void Main()
{
StampaCostoTotale(3m, 2.5m);
StampaCostoTotale(1m, 2m, 3.5m, 7.5m);
}
Il risultato delle due invocazioni sarà:
L'importo totale di tutti i libri è: 5.5
L'importo totale di tutti i libri è: 14.0
Poiché prezzi
è un array, si può presumere che possiamo dichiarare e inizializzare un array prima dell'invocazione del nostro metodo. Poi passare quell'array come argomento:
static void Main()
{
decimal[] arrayPrezzi = new decimal[] { 3m, 2.5m };
// Passaggio di un array inizializzato come var-arg:
StampaCostoTotale(arrayPrezzi);
}
Quanto sopra è un'invocazione legale, e il risultato dell'esecuzione del codice è il seguente:
L'importo totale di tutti i libri è: 5.5
Posizione del Parametro Var-args
Un metodo, che ha un numero variabile di argomenti, può anche avere altri parametri nella sua lista dei parametri.
Il seguente codice, per esempio, ha come primo parametro un elemento di tipo string
, e subito dopo possono esserci uno o più parametri di tipo int
:
static void Esempio(string parametroStr, params int[] x)
{
// ...
}
L'unico vincolo da rispettare è che l'elemento della lista dei parametri nella definizione del metodo, che permette il passaggio di un numero variabile di argomenti, deve sempre essere posizionato alla fine della lista dei parametri.
Posizione del Parametro Var-args
L'elemento della lista dei parametri, che permette il passaggio di un numero variabile di argomenti tramite l'invocazione di un metodo, deve sempre essere dichiarato alla fine della lista dei parametri del metodo.
Quindi, se proviamo a mettere la dichiarazione del parametro var-args x
, mostrato nell'ultimo esempio, non all'ultimo posto, così:
static void Esempio(params int[] x, string parametroStr)
{
// ...
}
Il compilatore restituirà il seguente messaggio di errore:
error CS0231: A params parameter must be the last parameter in a parameter list
Limitazioni sul Numero per gli Argomenti Variabili
Un'altra limitazione, per i metodi con numero variabile di argomenti, è che il metodo non può avere nella sua dichiarazione più di un parametro che permette il passaggio di numeri variabili di argomenti.
Quindi se proviamo a compilare un metodo dichiarato nel seguente modo:
static void Esempio(params int[] x, params string[] z)
{
// ...
}
Il compilatore restituirà il messaggio di errore già visto sopra:
error CS0231: A params parameter must be the last parameter in a parameter list
Questa regola può essere considerata come un caso speciale della regola per la posizione dei var-args, cioè il parametro correlato deve essere alla fine della lista dei parametri.
Lista dei Parametri Vuota
Dopo aver familiarizzato con la dichiarazione e l'invocazione di metodi con numero variabile di argomenti, sorge un'altra domanda: cosa succederebbe se invocassimo tale metodo, ma senza parametri?
Per esempio, quale sarebbe il risultato dell'invocazione del nostro metodo che calcola la somma dei prezzi dei libri, nel caso in cui non ci piacesse nessun libro:
static void Main()
{
StampaCostoTotale();
}
Come si può vedere questo codice viene compilato senza errori e dopo la sua esecuzione il risultato è il seguente:
L'importo totale di tutti i libri è: 0
Questo accade perché, sebbene non abbiamo passato alcun valore al nostro metodo, tramite la sua invocazione, l'array decimal[] prezzi
viene creato, ma è vuoto (cioè non consiste di alcun elemento).
Questo è un dettaglio fondamentale da ricordare , perché anche se non abbiamo inizializzato l'array, C# si occupa di farlo lo stesso per l'array che deve contenere i parametri.
Parametri Var-args e Main
Tenendo presente come definiamo i metodi con numero variabile di argomenti, possiamo scrivere il metodo Main() di un programma C# nel seguente modo:
static void Main(params string[] args)
{
// Il corpo del metodo viene qui
}
La definizione sopra è valida ed è accettata senza errori dal compilatore.
In Sintesi
In questa lezione abbiamo studiato che:
- Un metodo con un numero variabile di argomenti è un metodo che può essere invocato con un numero diverso di argomenti, ogni volta che viene chiamato.
- La dichiarazione di un metodo con un numero variabile di argomenti è simile a quella di qualsiasi altro metodo, ma la lista dei parametri è dichiarata con la parola chiave
params
. - Il parametro
params
deve essere l'ultimo parametro nella lista dei parametri del metodo. - Un metodo può avere solo un parametro
params
. - Un metodo con un numero variabile di argomenti può essere invocato senza argomenti.
- Un metodo con un numero variabile di argomenti può essere invocato con un numero diverso di argomenti, ogni volta che viene chiamato.
Nella prossima lezione, vedremo come dichiarare e usare i parametri opzionali e i parametri con nome in C#.