I metodi che abbiamo visto nella precedente lezione, svolgevano egregiamente il loro compito cioè, elaboravano tutto il blocco di codice al loro interno e terminavano la loro esecuzione lasciando il prosieguo alla prima istruzione successiva la loro invocazione.

Ma alcune volte può capitare che, per un evento eccezionale o per una qualsiasi ragione logica, si vuole far terminare l’elaborazione del codice di un metodo anticipatamente. Il linguaggio ci consente la terminazione prematura di un metodo tramite l’istruzione return; inserita nel punto in cui si è deciso di terminare l’esecuzione.

La sintassi è:

return valore-o-espressione-di-ritornoopz. ;

oppure solo

return;

L’istruzione altera il normale flusso di elaborazione del metodo provocandone l’immediata uscita ritornando alla prima istruzione utile dopo quella di invocazione.

Se la usassimo all’interno del metodo Main(), provocherebbe l’immediata chiusura del programma, restituendo il controllo al sistema operativo.

Per fare un banale esempio, si potrebbe creare un metodo che calcoli la radice quadrata di un numero e nel caso in cui il radicando fosse un numero negativo, si potrebbe interrompere il flusso del metodo evitando così la generazione di errori da parte del sistema. Possiamo anche, tramite la prima forma dell’istruzione quella cioè che permette il ritorno di un valore, comunicare al codice che ha invocato il metodo di effettuare l’analisi di questo valore per prendere eventuali decisioni in merito. Nella fattispecie, potremmo far ritornare un valore minore di zero che il restante codice può interpretare come un qualcosa che non è andato a buon fine (radicando negativo).

Metodi parametrizzati

Fino ad ora abbiamo utilizzato metodi che venivano invocati semplicemente tramite il loro nome, in questo modo:

nome-metodo();

le parentesi che seguono il nome del metodo, stanno ad indicare che potrebbero contenere qualcosa. Questo "qualcosa" rappresenta un sistema di comunicazione tra il codice ed il metodo da esso invocato.

Il sistema ci consente di comunicare dei valori che verranno utilizzati all’interno del blocco di codice del metodo invocato. Ad esempio possiamo modificare il programma della precedente lezione, cioè Circonferenza.cs, al quale modificheremo, a loro volta, i due metodi rendendoli parametrizzati.

Ecco il codice del nuovo programma:

N.R.

Codice sorgente Circo_param.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
43
44
45
46
47

// questo programma calcola
// l'area e la lunghezza di una // circonferenza
using System; class Circonferenza { // dichiaro e inizializzo le variabili static double raggio=0; static double area=0; static double circonf=0; // la costante PI greco const double PI=3.14159; // 1° metodo per il calcolo dell'area static void Area(double rag) { area=PI*rag*rag; } // 2° metodo per la circonferenza static void Circonf(double rag) { circonf=2*PI*rag; } static void Main() // metodo principale del programma (entry point) { Console.WriteLine("\nCalcola l'area e la lunghezza di una circonferenza"); Console.Write("Inserisci il raggio "); raggio=Convert.ToDouble(Console.ReadLine()); // invoca il 1° metodo con il // passaggio del valore del raggio Area(raggio); // invoca il 2° metodo con il // passaggio del valore del raggio Circonf(raggio); Console.WriteLine("\nL'area della circonferenza è {0}",area); Console.WriteLine("\nLa lunghezza della circonferenza è {0}",circonf); Console.ReadLine(); } }

 

Le modifiche apportate al codice, riguardano le signature dei metodi dove compare, tra parentesi, la dichiarazione del parametro (in rosso) che il metodo userà (righe 18 e 25).

Mentre nell’invocazione dei metodi (riga 38 e 42), compare l’argomento che verrà passato come parametro al metodo invocato e deve essere dello stesso tipo del parametro del metodo.

In generale, facendo riferimento al nostro esempio, possiamo cosi schematizzare il funzionamento dei metodi parametrizzati:

 

cioè l’argomento relativo all’invocazione del primo metodo, raggio, verrà associato (copiato) nel parametro dello stesso tipo rag del metodo Area, mentre l’argomento della seconda invocazione, verrà associato al parametro rag del metodo Circonf.

La scelta del nome dei parametri (rag) è stata effettuata per rendere chiaro il fatto che si trattava del raggio del circonferenza e comunque non hanno nessuna relazione perché "vivono" in ambiti del tutto differenti.

La comunicazione che avviene tra l’invocazione e l’esecuzione del metodo, ha la caratteristica di passare un valore al metodo che lo utilizzerà nel suo codice. In gergo tecnico viene definita

passaggio per valore

cioè il metodo usufruirà del valore passato senza che esso sia modificato pur essendo manipolato all’interno del blocco di codice. Quindi l’argomento dell’invocazione del metodo, non potrà mai essere modificato mantenendo inalterato il suo valore.

Come vedremo più avanti, questo sistema, spesso potrebbe essere una restrizione in quanto potremmo avere bisogno che il metodo invocato possa modificare l’argomento passato. Ma andiamo con ordine.

I due metodi che abbiamo utilizzato nell’esempio precedente, hanno la caratteristica di non ritornare nessun valore. Nella loro dichiarazione è stata usata la parola chiave void che sta ad indicare appunto che il metodo non produce alcun valore frutto dell’elaborazione. Nella programmazione reale utilizzare dei valori di ritorno è una prassi più che comune. Per dichiarare un metodo che ritorna un valore si adotta la seguente sintassi:

modificatore tipo nome-metodo(elenco parametri)

dove al posto di tipo dovremo dichiarare il tipo del valore che il metodo ci ritorna. Il valore di ritorno sarà l’argomento della parola chiave return, vista in precedenza,

Possiamo ora modificare il nostro programma inserendo return all’interno del codice. Prima di tutto ridichiariamo il primo metodo

static double Area(double rag)

ciò ci conferma che avremo un valore di ritorno di tipo double. Inseriamo la parola chiave return nel codice del metodo, e questo è il risultato:

static double Area(double rag)
  {
      return (PI*rag*rag); 
   }

Come si vede, l’argomento di return è una espressione, normalmente poteva essere anche una variabile dichiarata, ovviamente, double, ma il concetto non cambia. La stessa cosa facciamo con il secondo:

static double Circonf(double rag)
   {
      return (2*PI*rag); 
     }

Adesso il codice del programma:

N.R.

Codice sorgente Circo_ret.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

using System;
class Circonferenza
    {
              // dichiaro e inizializzo le variabili 
              static double raggio=0;
              
              // la costante PI greco 
              const double PI=3.14159;
              
               // 1° metodo per il calcolo dell'area 
              
              static double Area(double  rag)
              {
              return (PI*rag*rag);
              }
             
              // 2° metodo per la circonferenza 
              
              static double Circonf(double  rag)
               {
                  return (2*PI*rag);
                }
 
static void Main() // metodo principale del programma (entry point)
    {
        Console.WriteLine("\nCalcola l'area e la lunghezza di una circonferenza");
        Console.Write("Inserisci il raggio ");
        raggio=Convert.ToDouble(Console.ReadLine());
        // stampo direttamente i valori di ritorno dei metodi 
        Console.WriteLine("\nL'area della circonferenza è {0}",Area(raggio));
        Console.WriteLine("\nLa lunghezza della circonferenza è {0}",Circonf(raggio));
        Console.ReadLine();
     }
  }

Vorrei soffermarmi sulle istruzioni di stampa di riga 30 e 31; come notate compaiono direttamente le chiamate ai due metodi che, ritornando dei valori, possono tranquillamente essere utilizzati come argomenti di stampa. Trattandosi di valori di ritorno frutto dell’elaborazione di metodi, potevo assegnarli a delle variabili (dello stesso tipo) con una normale istruzione di assegnazione, per esempio:

area=Area(raggio);

e successivamente stampare le variabili. Va da se che l’uso di una variabile, in questo contesto, sarebbe stata inutile e ridondante quindi ho preferito stampare direttamente i valori di ritorno.

Per tale motivo ho eliminato dalle dichiarazioni le due variabili area e circonf rendendo il codice più corto e più leggibile.

Nella prossima lezione, faremo in modo di utilizzare argomenti che verranno in qualche modo modificati dal metodo invocato con la tecnica del passaggio per riferimento.


Pagina precedente - Pagina successiva