Passaggio per riferimento
Passaggio per valore e per riferimento
Per default, C# passa i parametri per valore: il metodo riceve una copia della variabile originale, quindi le modifiche non influenzano chi ha chiamato il metodo.
void Raddoppia(int n) { n = n * 2; // modifica solo la copia locale } int x = 5; Raddoppia(x); Console.WriteLine(x); // stampa ancora 5
Per permettere a un metodo di modificare la variabile originale si
usano le parole chiave ref e out.
ref
ref indica che il parametro e' un alias della variabile originale:
leggere o scrivere il parametro dentro il metodo equivale a leggere o
scrivere la variabile del chiamante.
Regole fondamentali:
- La variabile deve essere inizializzata prima di essere passata.
- La parola chiave
refva scritta sia nel prototipo del metodo che nella chiamata.
void Raddoppia(ref int n) { n = n * 2; // modifica la variabile originale } int x = 5; Raddoppia(ref x); Console.WriteLine(x); // stampa 10
Esempio: scambio di due variabili
Un caso classico in cui ref e' necessario e' la funzione di scambio
(swap): senza ref sarebbe impossibile modificare entrambe le variabili
originali.
static void Scambia(ref int a, ref int b) { int temp = a; a = b; b = temp; } int x = 10, y = 20; Scambia(ref x, ref y); Console.WriteLine($"x = {x}, y = {y}"); // x = 20, y = 10
Esempio: contatore condiviso
ref e' utile quando piu' chiamate successive devono aggiornare la
stessa variabile senza usare variabili globali.
static void Incrementa(ref int contatore, int quanto) { contatore += quanto; } int totale = 0; Incrementa(ref totale, 3); Incrementa(ref totale, 7); Console.WriteLine(totale); // 10
out
out serve quando il metodo deve restituire piu' di un valore. A
differenza di ref:
- La variabile non deve essere inizializzata prima della chiamata.
- Il metodo e' obbligato ad assegnare un valore al parametro
outprima di terminare.
static void MinMax(int[] arr, out int min, out int max) { min = arr[0]; max = arr[0]; foreach (int val in arr) { if (val < min) min = val; if (val > max) max = val; } } int[] numeri = { 4, 1, 9, 2, 7 }; int minimo, massimo; // non serve inizializzare MinMax(numeri, out minimo, out massimo); Console.WriteLine($"Min: {minimo}, Max: {massimo}"); // Min: 1, Max: 9
Esempio: int.TryParse
Il metodo int.TryParse della libreria standard e' un esempio reale e
molto comune di out: restituisce true se la conversione ha avuto
successo e scrive il risultato nel parametro out.
Console.Write("Inserisci un numero: "); string testo = Console.ReadLine(); int numero; if (int.TryParse(testo, out numero)) { Console.WriteLine($"Hai inserito il numero {numero}."); } else { Console.WriteLine("Input non valido."); }
ref vs out: confronto
| Caratteristica | ref |
out |
|---|---|---|
| Variabile deve essere inizializzata | Si' | No |
| Il metodo deve assegnare un valore | No | Si' |
| Uso tipico | Modificare un valore esistente | Restituire piu' valori |
// ref: x deve gia' avere un valore int x = 5; Raddoppia(ref x); // out: y puo' essere non inizializzata int y; Calcola(out y);