Come abbiamo visto nelle lezioni precedenti, gli argomenti dell’invocazione di un metodo non vengono modificati quando essi vengono passati per valore al metodo. Ma a volte può capitare che questi valori debbano essere modificati, consentendo così al codice che segue l’invocazione di poter gestire i medesimi in qualche elaborazione.

Il C# mette a disposizione una parola chiave che consente ad un metodo di modificare i suoi parametri; la parola chiave è ref che cambia un poco la segnatura del metodo e la sua invocazione.

La segnatura generale del metodo diventa

modificatoreopz tipo-di-ritorno nome_metodo (ref tipo var1, ecc..)
{
  //codice
}

dove modificatoreopz è il modificatore di accesso (public, private, ecc..), tipo-di-ritorno rappresenta il tipo (int, double, char, ecc..) di ritorno del metodo. Se il metodo non ritorna alcun valore, si deve scrivere void.

nome_metodo è il nome del metodo da noi attribuito.

Nelle parentesi tonde compare la parola chiave ref che precede il tipo ed il nome del parametro che nella segnatura è var1. Ciò sta a significare che una modifica a tale parametro all’interno del metodo, si rifletterà anche sul corrispondente argomento dell’invocazione del metodo medesimo.

Le cose cambiano anche per quel che riguarda l’invocazione del metodo; tutti gli argomenti che devono essere passati per riferimento, devono essere preceduti da ref.

Facciamo subito un esempio.

Il codice seguente incrementa semplicemente due variabili intere passate per riferimento ad un metodo il quale non ha altra funzione che effettuare l’incremento stesso dei suoi parametri.

Questo è il codice:

Codice sorgente PerRiferimento.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

using System;

class PerRiferimento

{

// variabile globale

static int num1=0;

 

// variabile globale

static double num2=0;

 

static void Incrementa(ref int num1, ref double num2)

{

Console.Write("\n\t--- Ingresso nel metodo ---\n");

// incremento dei valori

++num1;

++num2;

Console.Write("\nI parametri sono stati incrementati valgono {0} e {1}\n",num1,num2);

Console.Write("\n\t--- Uscita dal metodo ---\n");

}

 

static void Main() // entry point

{

 

Console.Write("\n\nGli argomenti prima dell'invocazione sono: {0} e {1}\n",num1,num2);

 

Incrementa(ref num1,ref num2); // invocazione del metodo

 

Console.Write("\nGli argomenti dopo l'invocazione sono: {0} e {1}\n\n",num1,num2);

 

}

}

Dopo averlo compilato (senza i numeri di riga!) e lanciato, questo il risultato:

Schermata esempio 1

Il programma implementa un metodo, Incrementa(..), alla riga 10, che ha entrambi i parametri dichiarati per riferimento (ref) che vengono incrementati al suo interno (riga 14 e 15) e visualizzati alla riga 16. La sua invocazione, alla riga 25, presenta anch’essa i due argomenti dichiarati per riferimento. Come si vede dalla figura, dopo l’esecuzione del metodo, le due variabili dichiarate hanno subito una modifica questo a conferma di quanto affermato.

Considerando la poca utilità del programma presentato, vorrei presentarvi un programmino un po’ più concreto che, nella sua logica, potrebbe essere utile come algoritmo per altri programmi (p.es. ordinamento).

Il programma consente di scambiare il contenuto di due variabili intere inserite dall’utente; il programma si chiama swap.cs .

Questo è il codice:

Codice sorgente swap.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

using System;

class Swap

{

// variabile globale

static int num1=0;

 

// variabile globale

static int num2=0;

 

static void LeggiNum()

{

Console.Write("\nInserire il primo valore ");

 

num1=Convert.ToInt32(Console.ReadLine());

 

Console.Write("\nInserire il secondo valore ");

num2=Convert.ToInt32(Console.ReadLine());

 

}

 

static void Swapnum( ref int num1, ref int num2)

{

int temp;

// effettua lo scambio

temp=num1;

num1=num2;

num2=temp;

}

 

static void Main()

{

 

LeggiNum(); // acquisisce i valori

 

Console.Write("\n\nGli argomenti prima dell'invocazione sono: {0} e {1}\n",num1,num2);

 

Swapnum(ref num1, ref num2); // invocazione del metodo per lo scambio

 

Console.Write("\nGli argomenti dopo l'invocazione sono: {0} e {1}\n\n",num1,num2);

 

}

}

in figura un esempio:

Schermata esempio 2

Nel codice compaiono le dichiarazioni di due metodi, LeggiNum() e Swapnum(..), rispettivamente alla riga 10 che consente di inserire i valori richiesti, e alla riga 21 che consente di effettuare lo scambio (swap) dei valori contenuti nella variabili globali num1 e num2. Sia il metodo Swapnum(..) che la sua invocazione di riga 37, contengono le variabili passate come riferimento e che risulteranno modificate come si vede in figura.

E’ il momento di fare qualche considerazione.

Sia per il passaggio di parametri per valore che per riferimento,

  1. l’argomento deve essere dello stesso tipo del rispettivo parametro
  2. deve essere una variabile
  3. ogni argomento deve essere definito

Per quello che riguarda, invece, i parametri passati per riferimento, bisogna tenere sempre presente che la parola chiave ref deve comparire sia nell’invocazione che nella segnatura del metodo.

Nel passaggio di parametri per valore tra l’invocazione di un metodo e la sua esecuzione, avviene una comunicazione di tipo unidirezionale: il metodo acquisisce le copie dei valori degli argomenti, effettua l’elaborazione e non restituisce nulla al codice chiamante. Mentre nel passaggio di parametri per riferimento avviene una comunicazione di tipo bidirezionale in quanto il metodo invocato restituisce al codice eventuali valori modificati, che il codice stesso può continuare ad elaborare in altri contesti.

L’argomento metodi non finisce qui perché bisogna rispondere alla seguente domanda:

"Può un metodo ritornare più di un valore?"

Come sappiamo, tramite la parola chiave return, un metodo ritorna un solo valore al codice chiamante, ma il C# ci consente di fare di più. Lo vedremo nella prossima lezione.


Pagina precedente - Pagina successiva