Prima di entrare nel vivo dell’argomento odierno cioè "i metodi", è necessario completare il discorso intrapreso sui campi di una classe.

Faccio un breve riepilogo.

Ho parlato, nelle lezioni precedenti, dei "campi istanza", cioè di variabili che vengono dichiarate in una classe e che sono poi utilizzate dagli oggetti (appartengono agli oggetti ) che andremo ad istanziare. Successivamente ho completato il discorso su come accedere a questi campi, una volta resi privati (private), tramite le proprietà.

C’è un particolare tipo di variabile che non appartiene ad un oggetto istanziato ma appartiene alla classe che l’ha definita,

le variabili statiche.

Quando istanziamo una classe, viene creata una copia dei membri per ogni oggetto creato, quindi ogni campo, sarà di pertinenza dell’oggetto creato.

Con una variabile statica, si vuole dichiarare un campo di pertinenza della classe e non dell’oggetto istanziato. Ciò significa che non verrà creata nessuna copia di questa variabile ed il suo utilizzo si rifletterà automaticamente su tutti gli oggetti istanziati: questo è un modo di rendere un campo comune a tutti gli oggetti creati.

La sintassi è questa:

static public tipo nome_campo;

L’accesso ad una variabile statica non avviene tramite l’oggetto istanziato, ma tramite il nome della classe stessa seguendo sempre la sintassi della notazione puntata.

Per esempio:

 class Veicolo// dichiaro la classe
{
   ........
   // dichiarazione della variabile statica
   static public int num_veicoli=0;
   ………
}

class Auto // programma
{
    public static void Main()
     {
       Veicolo Car1=new Veicolo();   // istanzio un oggetto
       ……………
       // assegnazione della variabile istanza
       Veicolo.num_veicoli+=1;
       .........
     }
}

Di solito una variabile statica viene utilizzata come contatore. Più avanti ne faremo uso in alcuni esempi un po’ più concreti.

E’ arrivato il momento di entrare nel vivo dell’argomento che riguarda i metodi.

Tutti i programmi scritti fino ad ora, non hanno avuto grosse funzionalità se non quelle di stampare sul monitor dei dati o acquisirne degli altri da tastiera. Queste funzionalità ci hanno permesso di effettuare delle operazioni tramite la chiamata di una porzione di codice atto ad implementarle. Per fare un esempio, basti ricordare la procedura di stampa di una semplice stringa di testo:

Console.WriteLine("Ciao a tutti, benvenuti in docenti.org");

Questa istruzione è composta da tre parti:

  1. Console – classe a cui appartengono le funzionalità di stampa e/o acquisizione dell’input da tastiera, ecc.
  2. WriteLinefunzione (metodo) che implementa il codice di stampa
  3. stringa – è la stringa (o dati) che verranno stampati sul monitor.

L’istruzione richiama la funzione WriteLine della classe Console che stamperà appunto la stringa contenuta tra i doppi apici.

In generale in tutti i linguaggi di programmazione, una funzione è una porzione di codice che viene richiamato per effettuare delle particolari elaborazioni (funzionalità) distaccandosi momentaneamente dal normale flusso del programma per poi ritornare, una volta terminata l’elaborazione, all’istruzione successiva alla chiamata della funzione.

Utilizzando le funzioni, non si ha più un blocco di codice monolitico che potrebbe diventare molto complesso da "gestire" (pensate ad applicazioni con milioni di righe di codice), ma il programma viene spezzettato in tante funzioni (tanti sottoprogrammi) che elaborano una porzione di codice che implementa una particolare funzionalità.

L’istruzione precedente fa proprio questo: richiama la funzione WriteLine che esegue il codice al suo interno distaccandosi dal normale flusso del programma, stampa la stringa e ritorna all’istruzione immediatamente successiva alla chiamata della funzione stessa.

WriteLine è una delle migliaia di funzioni predefinite scritte dai programmatori del linguaggio C#, ma nessuno ci vieta di scriverne di personali anzi è quasi un obbligo di programmazione.

Nel C# (come in Java), tali funzioni vengono chiamate

metodi

e da questo momento in poi ci adegueremo a tale terminologia.

Ora è il caso di fare subito un esempio facile facile. Andiamo a ripescare il primo programma che è stato scritto all’inizio di questo corso e che qui riporto:

N.R.

Codice sorgente CiaoProf.cs

1
2
3
4
5
6
7
8
9
10
11

using System;
// inizio 
public class CiaoProf
{
   public static void Main()
     {
           Console.WriteLine("Ciao Prof., benvenuti in Docenti.org");
           // attende che si digiti un qualsiasi carattere o return
          Console.ReadLine();
      }
}

 

lo dotiamo ora di un metodo che "realizza" la stampa:

N.R.

Codice sorgente CiaoProf2.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

using System;
// inizio
public class CiaoProf2
{
  static void Stampa()       // dichiarazione del metodo
   {
      Console.WriteLine("\nCiao Prof., benvenuti in Docenti.org");
   }
  
  public static void Main() // metodo principale del programma
    {
        Stampa();    // richiama il metodo
                
        // attende che si digiti un qualsiasi carattere o return
        Console.ReadLine();
     }
 }

 

E’ stato inserito un metodo (in rosso) chiamato Stampa(). Le parentesi tonde vuote (), stanno a significare che il metodo non ha parametri (poi vedremo cosa sono e come si usano). Il blocco di codice al suo interno, delimitato da una coppia di parentesi graffe, contiene una sola istruzione, nella riga 7, che noi conosciamo bene e che a sua volta richiama un altro metodo, il metodo WriteLine.

Come potete vedere, il metodo Stampa() è stato inserito all’esterno del più famoso metodo Main(). In questo caso, il metodo è stato inserito prima ma poteva tranquillamente essere inserito dopo il metodo Main(), non ha nessuna importanza.

A tal proposito il metodo Main() deve comparire necessariamente in tutte le nostre applicazioni, grandi o piccole che siano, perché tale metodo è il primo metodo che viene eseguito e che contiene tutta la logica del programma.

Detto questo, esaminiamo la riga 12; in essa compare la chiamata del metodo: Stampa(); . Tale chiamata, "dirotta" l’esecuzione del codice alla riga 5 dove, a parte il modificatore di accesso static che poi vedremo, compare la parola chiave void. Essa ci indica che il metodo relativo, non ritorna alcun valore ma si limita ad eseguire tutte le istruzioni in esso contenute. Nel nostro piccolo esempio, viene eseguita solamente l’istruzione della riga 7, dopodichè il controllo del flusso ritorna all’istruzione immediatamente seguente quella della chiamata al metodo, cioè l’istruzione della riga 15 che, guarda caso, è ancora una chiamata ad un "ennesimo" metodo. Vi ricordo che il compilatore non tiene conto dei commenti ma compila solo il codice attivo: le istruzioni.

Definizione di un metodo.

Definire un metodo significa dotare di una nuova funzionalità il contesto in cui è stato definito o a cui appartiene (programma e/o classe).

La definizione generale di un metodo è questa:

 modificatoreopz  tipo-di-ritorno nome-del-metodo (lista dei parametriopz) 
    {
         // istruzioni
     }

dove il

  1. modificatoreopz è il modificatore di accesso (opzionale) come static, protected ecc...
  2. tipo-di-ritorno è il tipo di dato (int, double, float, ecc.) che il metodo ritorna. Se non ritorna alcun valore, bisogna utilizzare la parola chiave void.
  3. nome-del-metodo è il nome che daremo al metodo e che dovrebbe essere descrittivo della funzionalità svolta come, ad esempio, Area(....), CalcolaStipendio(....), ecc.
  4. (lista dei parametriopz) è l’elenco (opzionale) di parametri (che poi vedremo) che saranno utilizzati all’interno del metodo.

Nel corpo del metodo, racchiuse nelle parentesi graffe, compaiono tutte le istruzioni che effettueranno l’elaborazione della funzionalità e se il metodo ha bisogno di ritornare un determinato valore frutto dell’elaborazione medesima, l’ultima istruzione sarà sempre

return variabile;

Quest’ultima istruzione consente, al programma principale e/o metodo che lo invoca, di recuperare un valore che servirà per il resto del codice.

Come al solito facciamo subito un esempio.

"Vogliamo scrivere un programma che calcoli, dato il raggio, l’area e la lunghezza di una circonferenza."

Per prima cosa scriviamo il codice relativo al primo metodo che calcola l’area della circonferenza, potrebbe essere questo:

 static void Area()
    {
        area=PI*raggio*raggio;
     }

dove area è una variabile di tipo double dichiarata all’interno dell’applicazione (classe programma) e conterrà appunto l’area 1;

PI può essere definita come costante di tipo double, essa rappresenterà il Pi-greco;

raggio è una variabile, dichiarata come area e sarà il raggio della nostra circonferenza che forniremo tramite tastiera (quindi in input).

Il secondo metodo calcolerà la lunghezza della circonferenza e potrebbe essere questo:

static void Circonf()
   {
       circonf=2*PI*raggio;
    }

dove circonf è una variabile di tipo double che conterrà il valore richiesto.

Ora riuniamo tutto il codice.

Questo è il codice completo del programma. Copiatelo, compilatelo e lanciatelo.

N.R.

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

// 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()
              {
                   area=PI*raggio*raggio;
               }

              // 2° metodo per la circonferenza

            static void Circonf()
               {
                  circonf=2*PI*raggio;
                }

     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());
              Area();  // invoca il 1° metodo
              Circonf();  // invoca il 2° metodo
              Console.WriteLine("\nL'area della circonferenza è {0}",area);
              Console.WriteLine("\nLa lunghezza della circonferenza è {0}",circonf);
              Console.ReadLine();
          }
   }

Il programma funziona bene anche se, come è evidente, non compare nessuna gestione degli errori. Per il momento basta capire il funzionamento iniziale dei metodi e lascio al lettore il compito di apprendere il significato del codice.

L’argomento non si esaurisce qui. Nella prossima lezione ci occuperemo di migliorare il programma qui proposto utilizzando metodi parametrizzati ed altri nuovi concetti.



Indietro
1 Il nome della variabile non può confondersi con quello del metodo perché la prima lettera è minuscola e per il C# non hanno niente in comune.

Pagina precedente - Pagina successiva