Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Guida al Visual Basic .NET - I Metodi Parte I

Guida al Visual Basic .NET

Capitolo 13° - I Metodi Parte I

<< Precedente Prossimo >>

Anatomia di un metodo

Il Framework .NET mette a disposizione dello sviluppatore un enorme numero di classi contenenti metodi davvero utili, già scritti e pronti all'uso, ma solo in pochi casi questi bastano a creare un'applicazione ben strutturata ed elegante. Per questo motivo, è possibile creare nuovi metodi - procedure o funzioni che siano - ed usarli comodamente nel programma. Per lo più, si crea un metodo per separare logicamente una certa parte di codice dal resto del sorgente: questo serve in primis a rendere il listato più leggibile, più consultabile e meno prolisso, ed inoltre ha la funzione di racchiudere sotto un unico nome (il nome del metodo) una serie più o meno grande di istruzioni.
Un metodo è costituito essenzialmente da tre parti:
  • Nome : un identificatore che si può usare in altre parti del programma per invocare il metodo, ossia per eseguire le istruzioni di cui esso consta;
  • Elenco dei parametri : un elenco di variabili attraverso i quali il metodo può scambiare dati con il programma;
  • Corpo : contiene il codice effettivo associato al metodo, quindi tutte le istruzioni e le operazioni che esso deve eseguire
Ma ora scendiamo un po' più nello specifico...


Procedure senza parametri

Il caso più semplice di metodo consiste in una procedura senza parametri: essa costituisce, grosso modo, un sottoprogramma a sè stante, che può essere richiamato semplicemente scrivendone il nome. La sua sintassi è molto semplice:
Sub [nome]()
    'istruzioni
End Sub 
Credo che vi sia subito balzato agli occhi che questo è esattamente lo stesso modo in cui viene dichiarata la Sub Main: pertanto, ora posso dirlo, Main è un metodo e, nella maggior parte dei casi, una procedura senza parametri (ma si tratta solo di un caso particolare, come vedremo fra poco). Quando il programma inizia, Main è il primo metodo eseguito: al suo interno, ossia nel suo corpo, risiede il codice del programma. Inoltre, poiché facenti parti del novero delle entità presenti in una classe, i metodi sono membri di classe: devono, perciò, essere dichiarati a livello di classe. Con questa locuzione abbastanza comune nell'ambito della programmazione si intende l'atto di dichiarare qualcosa all'interno del corpo di una classe, ma fuori dal corpo di un qualsiasi suo membro. Ad esempio, la dichiarazione seguente è corretta:
Module Module1
    Sub Esempio()
        'istruzioni
    End Sub
    
    Sub Main()
        'istruzioni
    End Sub
End Module 
mentre la prossima è SBAGLIATA:
Module Module1
    Sub Main()
        Sub Esempio()
            'istruzioni
        End Sub
        'istruzioni
    End Sub
End Module 
Allo stesso modo, i metodi sono l'unica categoria, oltre alle proprietà e agli operatori, a poter contenere delle istruzioni: sono strumenti "attivi" di programmazione e solo loro possono eseguire istruzioni. Quindi astenetevi dallo scrivere un abominio del genere:
Module Module1
    Sub Main()
        'istruzioni
    End Sub
    Console.WriteLine()
End Sub 
E' totalmente e concettualmente sbagliato. Ma ora veniamo al dunque con un esempio:
Module Module1
    'Dichiarazione di una procedura: il suo nome è "FindDay", il
    'suo elenco di parametri è vuoto, e il suo corpo è
    'rappresentato da tutto il codice compreso tra "Sub FindDay()"
    'ed "End Sub".
    Sub FindDay()
        Dim StrDate As String
        Console.Write("Inserisci giorno (dd/mm/yyyy): ")
        StrDate = Console.ReadLine

        Dim D As Date
        'La funzione Date.TryParse tenta di convertire la stringa
        'StrDate in una variabile di tipo Date (che è un tipo
        'base). Se ci riesce, ossia non ci sono errori nella
        'data digitata, restituisce True e deposita il valore
        'ottenuto in D; se, al contrario, non ci riesce,
        'restituisce False e D resta vuota.
        'Quando una data non viene inizializzata, dato che è un
        'tipo value, contiene un valore predefinito, il primo
        'Gennaio dell'anno 1 d.C. a mezzogiorno in punto.
        If Date.TryParse(StrDate, D) Then
            'D.DayOfWeek contiene il giorno della settimana di D
            '(lunedì, martedì, eccetera...), ma in un
            'formato speciale, l'Enumeratore, che vedremo nei
            'prossimi capitoli.
            'Il ".ToString()" converte questo valore in una
            'stringa, ossia in un testo leggibile: i giorni della
            'settimana, però, sono in inglese
            Console.WriteLine(D.DayOfWeek.ToString())
        Else
            Console.WriteLine(StrDate & " non è una data valida!")
        End If
    End Sub

    'Altra procedura, simile alla prima
    Sub CalculateDaysDifference()
        Dim StrDate1, StrDate2 As String
        Console.Write("Inserisci il primo giorno (dd/mm/yyyy): ")
        StrDate1 = Console.ReadLine
        Console.Write("Inserisci il secondo giorno (dd/mm/yyyy): ")
        StrDate2 = Console.ReadLine

        Dim Date1, Date2 As Date

        If Date.TryParse(StrDate1, Date1) And _
           Date.TryParse(StrDate2, Date2) Then
            'La differenza tra due date restituisce il tempo
            'trascorso tra l'una e l'altra. In questo caso noi
            'prendiamo solo i giorni
            Console.WriteLine((Date2 - Date1).Days)
        Else
            Console.WriteLine("Inserire due date valide!")
        End If
    End Sub

    Sub Main()
        'Command è una variabile di tipo char (carattere) che
        'conterrà una lettera indicante quale compito eseguire
        Dim Command As Char

        Do
            Console.Clear()
            Console.WriteLine("Qualche operazione con le date:")
            Console.WriteLine("- Premere F per sapere in che giorno " & _
                "della settimana cade una certa data;")
            Console.WriteLine("- Premere D per calcolare la differenza tra due date;")
            Console.WriteLine("- Premere E per uscire.")
            'Console.ReadKey() è la funzione che abbiamo sempre
            'usato fin'ora per fermare il programma in attesa della
            'pressione di un pulsante. Come vedremo fra breve, non 
            'è necessario usare il valore restituito da una
            'funzione, ma in questo caso ci serve. Ciò che 
            'ReadKey restituisce è qualcosa che non ho ancora
            'trattato. Per ora basti sapere che 
            'Console.ReadKey().KeyChar contiene l'ultimo carattere 
            'premuto sulla tastiera
            Command = Console.ReadKey().KeyChar
            'Analizza il valore di Command
            Select Case Command
                Case "f"
                    'Invoca la procedura FindDay()
                    FindDay()
                Case "d"
                    'Invoca la procedura CalculateDaysDifference()
                    CalculateDaysDifference()
                Case "e"
                    'Esce dal ciclo
                    Exit Do
                Case Else
                    Console.WriteLine("Comando non riconosciuto!")
            End Select
            Console.ReadKey()
        Loop
    End Sub
End Module 
In questo primo caso, le due procedure dichiarate sono effettivamente sottoprogrammi a sé stanti: non hanno nulla in comune con il modulo (eccetto il semplice fatto di esserne membri), né con Main, ossia non scambiano alcun tipo di informazione con essi; sono come degli ingranaggi sigillati all'interno di una scatola chiusa. A questo riguardo, bisogna inserire una precisazione sulle variabili dichiarate ed usate all'interno di un metodo, qualsiasi esso sia. Esse si dicono locali o temporanee, poiché esistono solo all'interno del metodo e vengono distrutte quando il flusso di elaborazione ne raggiunge la fine. Anche sotto questo aspetto, si può notare come le procedure appena stilate siano particolarmente chiuse e restrittive. Tuttavia, si può benissimo far interagire un metodo con oggetti ed entità esterne, e questo approccio è decisamente più utile che non il semplice impacchettare ed etichettare blocchi di istruzioni in locazioni distinte. Nel prossimo esempio, la procedura attinge dati dal modulo, poiché in esso è dichiarata una variabile a livello di classe.
Module Module1
    'Questa variabile è dichiarata a livello di classe 
    '(o di modulo, in questo caso), perciò è accessibile
    'a tutti i membri del modulo, sempre seguendo il discorso
    'dei blocchi di codice fatto in precedenza
    Dim Total As Single = 0

    'Legge un numero da tastiera e lo somma al totale
    Sub Sum()
        Dim Number As Single = Console.ReadLine
        Total += Number
    End Sub

    'Legge un numero da tastiera e lo sottrae al totale
    Sub Subtract()
        Dim Number As Single = Console.ReadLine
        Total -= Number
    End Sub

    'Legge un numero da tastiera e divide il totale per
    'tale numero
    Sub Divide()
        Dim Number As Single = Console.ReadLine
        Total /= Number
    End Sub

    'Legge un numero da tastiera e moltiplica il totale
    'per tale numero
    Sub Multiply()
        Dim Number As Single = Console.ReadLine
        Total *= Number
    End Sub

    Sub Main()
        'Questa variabile conterrà il simbolo matematico
        'dell'operazione da eseguire
        Dim Operation As Char
        Do
            Console.Clear()
            Console.WriteLine("Risultato attuale: " & Total)
            Operation = Console.ReadKey().KeyChar
            Select Case Operation
                Case "+"
                    Sum()
                Case "-"
                    Subtract()
                Case "*"
                    Multiply()
                Case "/"
                    Divide()
                Case "e"
                    Exit Do
                Case Else
                    Console.WriteLine("Operatore non riconosciuto")
                    Console.ReadKey()
            End Select
        Loop
    End Sub
End Module 


Procedure con parametri

Avviandoci verso l'interazione sempre maggiore del metodo con l'ambiente in cui esso esiste, troviamo le procedure con parametri. Al contrario delle precedenti, esse possono ricevere e scambiare dati con il chiamante: con quest'ultimo termine ci si riferisce alla generica entità all'interno della quale il metodo in questione è stato invocato. I parametri sono come delle variabili locali fittizie: esistono solo all'interno del corpo, ma non sono dichiarate in esso, bensì nell'elenco dei parametri. Tale elenco deve essere specificato dopo il nome del metodo, racchiuso da una coppia di parentesi tonde, e ogni suo elemento deve essere separato dagli altri da virgole.
Sub [nome](ByVal [parametro1] As [tipo], ByVal [parametro2] As [tipo], ...)
    'istruzioni
End Sub 
Come si vede, anche la dichiarazione è abbastanza simile a quella di una variabile, fatta eccezione per la parola riservata ByVal, di cui tra poco vedremo l'utilià. Per introdurre semplicemente l'argomento, facciamo subito un esempio, riscrivendo l'ultimo codice proposto nel paragrafo precedente con l'aggiunta dei parametri:
Module Module1
    Dim Total As Single = 0

    Sub Sum(ByVal Number As Single)
        Total += Number
    End Sub

    Sub Subtract(ByVal Number As Single)
        Total -= Number
    End Sub

    Sub Divide(ByVal Number As Single)
        Total /= Number
    End Sub

    Sub Multiply(ByVal Number As Single)
        Total *= Number
    End Sub

    Sub Main()
        'Questa variabile conterrà il simbolo matematico
        'dell'operazione da eseguire
        Dim Operation As Char
        Do
            Console.Clear()
            Console.WriteLine("Risultato attuale: " & Total)
            Operation = Console.ReadKey().KeyChar
            Select Case Operation
                'Se si tratta di simboli accettabili
                Case "+", "-", "*", "/"
                    'Legge un numero da tastiera
                    Dim N As Single = Console.ReadLine
                    'E a seconda dell'operazione, utilizza una
                    'procedura piuttosto che un'altra
                    Select Case Operation
                        Case "+"
                            Sum(N)
                        Case "-"
                            Subtract(N)
                        Case "*"
                            Multiply(N)
                        Case "/"
                            Divide(N)
                    End Select
                Case "e"
                    Exit Do
                Case Else
                    Console.WriteLine("Operatore non riconosciuto")
                    Console.ReadKey()
            End Select
        Loop
    End Sub
End Module 
Richiamando, ad esempio, Sum(N) si invoca la procedura Sum e si assegna al parametro Number il valore di N: quindi, Number viene sommato a Total e il ciclo continua. Number, perciò, è un "segnaposto", che riceve solo durante l'esecuzione un valore preciso, che può anche essere, come in questo caso, il contenuto di un'altra variabile. Nel gergo tecnico, Number - ossia, più in generale, l'identificatore dichiarato nell'elenco dei parametri - si dice parametro formale, mentre N - ossia ciò che viene concretamente passato al metodo - si dice parametro attuale. Non ho volutamente assegnato al parametro attuale lo stesso nome di quello formale, anche se è del tutto lecito farlo: ho agito in questo modo per far capire che non è necessario nessun legame particolare tra i due; l'unico vincolo che deve sussistere risiede nel fatto che parametro formale ed attuale abbiano lo stesso tipo. Quest'ultima asserzione, del resto, è abbastanza ovvia: se richiamassimo Sum("ciao") come farebbe il programma a sommare una stringa ("ciao") ad un numero (Total)?
Ora proviamo a modificare il codice precedente riassumendo tutte le operazioni in una sola procedura, a cui, però, vengono passati due parametri: il numero e l'operatore da usare.
Module Module1
    Dim Total As Single = 0

    Sub DoOperation(ByVal Number As Single, ByVal Op As Char)
        Select Case Op
            Case "+"
                Total += Number
            Case "-"
                Total -= Number
            Case "*"
                Total *= Number
            Case "/"
                Total /= Number
        End Select
    End Sub

    Sub Main()
        Dim Operation As Char
        Do
            Console.Clear()
            Console.WriteLine("Risultato attuale: " & Total)
            Operation = Console.ReadKey().KeyChar
            Select Case Operation
                Case "+", "-", "*", "/"
                    Dim N As Single = Console.ReadLine
                    'A questa procedura vengono passati due
                    'parametri: il primo è il numero da
                    'aggiungere/sottrarre/moltiplicare/dividere
                    'a Total; il secondo è il simbolo
                    'matematico che rappresenta l'operazione
                    'da eseguire
                    DoOperation(N, Operation)
                Case "e"
                    Exit Do
                Case Else
                    Console.WriteLine("Operatore non riconosciuto")
                    Console.ReadKey()
            End Select
        Loop
    End Sub
End Module 


Passare parametri al programma da riga di comando

Come avevo accennato in precedenza, non è sempre vero che Main è una procedura senza parametri. Infatti, è possibile dichiarare Main in un altro modo, che le consente di ottenere informazioni quando il programma viene eseguito da riga di comando. In quest'ultimo caso, Main viene dichiarata con un solo argomento, un array di stringhe:
Module Module1
    Sub Main(ByVal Args() As String)
        If Args.Length = 0 Then
            'Se la lunghezza dell'array è 0, significa che è vuoto
            'e quindi non è stato passato nessun parametro a riga
            'di comando. Scrive a schermo come utilizzare
            'il programma
            Console.WriteLine("Utilizzo: nomeprogramma.exe tuonome")
        Else
            'Args ha almeno un elemento. Potrebbe anche averne di
            'più, ma a noi interessa solo il primo.
            'Saluta l'utente con il nome passato da riga di comando
            Console.WriteLine("Ciao " & Args(0) & "!")
        End If
        Console.ReadKey()
    End Sub
End Module
Per provarlo, potete usare cmd.exe, il prompt dei comandi. Io ho digitato:
CD "C:UsersTotemDocumentsVisual Studio 2008ProjectsConsoleApplication2inDebug"
ConsoleApplication2.exe Totem
La prima istruzione per cambiare la directory di lavoro, la seconda l'invocazione vera e propria del programma, dove "Totem" è l'unico argomento passatogli: una volta premuto invio, apparirà il messaggio "Ciao Totem!". In alternativa, è possibile specificare gli argomenti passati nella casella di testo "Command line arguments" presente nella scheda Debug delle proprietà di progetto. Per accedere alle proprietà di progetto, cliccate col pulsante destro sul nome del progetto nella finestra a destra, quindi scegliete Properties e recatevi alla tabella Debug:

CommandLineDebug.jpg


<< Precedente Prossimo >>
A proposito dell'autore

C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...