Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
Guida al Visual Basic .NET - Le Strutture

Guida al Visual Basic .NET

Capitolo 17° - Le Strutture

<< Precedente Prossimo >>

Nel capitolo precedente ci siamo soffermati ad analizzare una particolare categoria di tipi di dato, gli enumeratori, strumenti capaci di rappresentare tramite costanti numeriche possibilità, scelte, opzioni, flags e in genere valori che si possano scegliere in un insieme finito di elementi. Le strutture, invece, appartengono ad un'altra categoria. Anch'esse rappresentano un tipo di dato derivato, o complesso, poiché non rientra fra i tipi base (di cui ho già parlato) ma è da essi composto. Le strutture ci permettono di creare nuovi tipi di dato che possano adattarsi in modo migliore alla logica dell'applicazione che si sta scrivendo: in realtà, quello che permettono di fare è una specie di "collage" di variabili. Ad esempio, ammettiamo di voler scrivere una rubrica, in grado di memorizzare nome, cognome e numero di telefono dei nostri principali amici e conoscenti. Ovviamente, dato che si tratta di tante persone, avremo bisogno di array per contenere tutti i dati, ma in che modo li potremmo immagazzinare? Per quello che ho illustrato fino a questo punto, la soluzione più lampante sarebbe quella di dichiarare tre array, uno per i nomi, uno per i cognomi e uno per i numeri telefonici.
Dim Names() As String
Dim Surnames() As String
Dim PhoneNumbers() As String 
Inutile dire che seguendo questo approccio il codice risulterebbe molto confusionario e poco aggiornabile: se si volesse aggiungere, ad esempio, un altro dato, "data di nascita", si dovrebbe dichiarare un altro array e modificare pressoch? tutte le parti del listato. Usando una struttura, invece, potremmo creare un nuovo tipo di dato che contenga al suo interno tutti i campi necessari:
Structure Contact
    Dim Name, Surname, PhoneNumber As String
End Structure

'...

'Un array di conttati, ognuno rappresentato dalla struttura Contact
Dim Contacts() As Contact 
Come si vede dall'esempio, la sintassi usata per dichiarare una struttura è la seguente:
Structure [Nome]
    Dim [Campo1] As [Tipo]
    Dim [Campo2] As [Tipo]
    '...
End Structure 
Una volta dichiarata la struttura e una variabile di quel tipo, però, come si fa ad accedere ai campi in essa presenti? Si usa l'operatore punto ".", posto dopo il nome della variabile:
Module Module1
    Structure Contact
        Dim Name, Surname, PhoneNumber As String
    End Structure

    Sub Main()
        Dim A As Contact

        A.Name = "Mario"
        A.Surname = "Rossi"
        A.PhoneNumber = "333 33 33 333"
    End Sub
End Module 
[Ricordate che le dichiarazioni di nuovi tipi di dato (fino ad ora quelli che abbiamo analizzato sono enumeratori e strutture, e le classi solo come introduzione) possono essere fatte solo a livello di classe o di namespace, e mai dentro ad un metodo.]
Una struttura, volendo ben vedere, non è altro che un agglomerato di più variabili di tipo base e, cosa molto importante, è un tipo value, quindi si comporta esattamente come Integer, Short, Date, eccetera... e viene memorizzata direttamente sullo stack, senza uso di puntatori.


Acrobazie con le strutture

Ma ora veniamo al codice vero e proprio. Vogliamo scrivere quella rubrica di cui avevo parlato prima, ecco un inizio:
Module Module1
    Structure Contact
        Dim Name, Surname, PhoneNumber As String
    End Structure

    Sub Main()
        'Contacts(-1) inizializza un array vuoto, 
        'ossia con 0 elementi
        Dim Contacts(-1) As Contact
        Dim Command As Char

        Do
            Console.Clear()
            Console.WriteLine("Rubrica -----")
            Console.WriteLine("Selezionare l'azione desiderata:")
            Console.WriteLine("N - Nuovo contatto;")
            Console.WriteLine("T - Trova contatto;")
            Console.WriteLine("E - Esci.")
            Command = Char.ToUpper(Console.ReadKey().KeyChar)
            Console.Clear()

            Select Case Command
                Case "N"
                    'Usa ReDim Preserve per aumentare le dimensioni
                    'dell'array mentenendo i dati già presenti.
                    'L'uso di array e di redim, in questo caso, è
                    'sconsigliato, a favore delle più versatili
                    'Liste, che però non ho ancora introdotto.
                    'Ricordate che il valore specificato tra
                    'parentesi indica l'indice massimo e non
                    'il numero di elementi.
                    'Se, all'inizio, Contacts.Length è 0,
                    'richiamando ReDim Contacts(0), si aumenta 
                    'la lunghezza dell'array a uno, poiché
                    'in questo caso l'indice massimo è 0,
                    'ossia quello che indica il primo e
                    'l'unico elemento
                    ReDim Preserve Contacts(Contacts.Length)

                    Dim N As Contact
                    Console.Write("Nome: ")
                    N.Name = Console.ReadLine
                    Console.Write("Cognome: ")
                    N.Surname = Console.ReadLine
                    Console.Write("Numero di telefono: ")
                    N.PhoneNumber = Console.ReadLine

                    'Inserisce nell'ultima cella dell'array
                    'l'elemento appena creato
                    Contacts(Contacts.Length - 1) = N

                Case "T"
                    Dim Part As String

                    Console.WriteLine("Inserire nome o cognome del " & _
                        "contatto da trovare:")
                    Part = Console.ReadLine

                    For Each C As Contact In Contacts
                        'Il confronto avviene in modalità
                        'case-insensitive: sia il nome/cognome
                        'che la stringa immessa vengono
                        'ridotti a Lower Case, così da
                        'ignorare la differenza tra
                        'minuscole e maiuscole, qualora presente
                        If (C.Name.ToLower() = Part.ToLower()) Or _
                           (C.Surname.ToLower() = Part.ToLower()) Then
                            Console.WriteLine("Nome: " & C.Name)
                            Console.WriteLine("Cognome: " & C.Surname)
                            Console.WriteLine("Numero di telefono: " & C.PhoneNumber)
                            Console.WriteLine()
                        End If
                    Next

                Case "E"
                    Exit Do

                Case Else
                    Console.WriteLine("Comando sconosciuto!")
            End Select
            Console.ReadKey()
        Loop
    End Sub
End Module 
Ora ammettiamo di voler modificare il codice per permettere l'inserimento di più numeri di telefono:
Module Module1
Structure Contact
        Dim Name, Surname As String
        'Importante: NON è possibile specificare le dimensioni
        'di un array dentro la dichiarazione di una struttura.
        'Risulta chiaro il motivo se ci si pensa un attimo.
        'Noi stiamo dichiarando quali sono i campi della struttura
        'e quale è il loro tipo. Quindi specifichiamo che
        'PhoneNumbers è un array di stringhe, punto. Se scrivessimo
        'esplicitamente le sue dimensioni lo staremmo creando
        'fisicamente nella memoria, ma questa è una
        'dichiarazione, come detto prima, e non una
        'inizializzazione. Vedremo in seguito che questa
        'differenza è molto importante per i tipi reference
        '(ricordate, infatti, che gli array sono tipi reference).
        Dim PhoneNumbers() As String
    End Structure

    Sub Main()
        Dim Contacts(-1) As Contact
        Dim Command As Char

        Do
            Console.Clear()
            Console.WriteLine("Rubrica -----")
            Console.WriteLine("Selezionare l'azione desiderata:")
            Console.WriteLine("N - Nuovo contatto;")
            Console.WriteLine("T - Trova contatto;")
            Console.WriteLine("E - Esci.")
            Command = Char.ToUpper(Console.ReadKey().KeyChar)
            Console.Clear()

            Select Case Command
                Case "N"
                    ReDim Preserve Contacts(Contacts.Length)

                    Dim N As Contact
                    Console.Write("Nome: ")
                    N.Name = Console.ReadLine
                    Console.Write("Cognome: ")
                    N.Surname = Console.ReadLine

                    'Ricordate che le dimensioni dell'array non
                    'sono ancora state impostate:
                    ReDim N.PhoneNumbers(-1)

                    'Continua a chiedere numeri di telefono finché
                    'non si introduce più nulla
                    Do
                        ReDim Preserve N.PhoneNumbers(N.PhoneNumbers.Length)
                        Console.Write("Numero di telefono " & N.PhoneNumbers.Length & ": ")
                        N.PhoneNumbers(N.PhoneNumbers.Length - 1) = Console.ReadLine
                    Loop Until N.PhoneNumbers(N.PhoneNumbers.Length - 1) = ""
                    'Ora l'ultimo elemento dell'array è sicuramente
                    'vuoto, lo si dovrebbe togliere.

                    Contacts(Contacts.Length - 1) = N

                Case "T"
                    Dim Part As String

                    Console.WriteLine("Inserire nome o cognome del " & _
                        "contatto da trovare:")
                    Part = Console.ReadLine

                    For Each C As Contact In Contacts
                        If (C.Name.ToLower() = Part.ToLower()) Or _
                           (C.Surname.ToLower() = Part.ToLower()) Then
                            Console.WriteLine("Nome: " & C.Name)
                            Console.WriteLine("Cognome: " & C.Surname)
                            Console.WriteLine("Numeri di telefono: ")
                            For Each N As String In C.PhoneNumbers
                                Console.WriteLine("  - " & N)
                            Next
                            Console.WriteLine()
                        End If
                    Next

                Case "E"
                    Exit Do

                Case Else
                    Console.WriteLine("Comando sconosciuto!")
            End Select
            Console.ReadKey()
        Loop
    End Sub
End Module 
In questi esempi ho cercato di proporre i casi più comuni di struttura, almeno per quanto si è visto fino ad adesso: una struttura formata da campi di tipo base e una composta dagli stessi campi, con l'aggiunta di un tipo a sua volta derivato, l'array. Fino ad ora, infatti, ho sempre detto che la struttura permette di raggruppare più membri di tipo base, ma sarebbe riduttivo restringere il suo ambito di competenza solo a questo. In realtà può contenere variabili di qualsiasi tipo, comprese altre strutture. Ad esempio, un contatto avrebbe potuto anche contenere l'indirizzo di residenza, il quale avrebbe potuto essere stato rappresentato a sua volta da un'ulteriore struttura:
Structure Address
    Dim State, Town As String
    Dim Street, CivicNumber As String
    Dim Cap As String
End Structure

Structure Contact
    Dim Name, Surname As String
    Dim PhoneNumbers() As String
    Dim Home As Address
End Structure 
Per accedere ai campi di Home si sarebbe utilizzato un ulteriore punto:
Dim A As Contact

A.Name = "Mario"
A.Surname = "Rossi"
ReDim A.PhoneNumbers(0)
A.PhoneNumbers(0) = "124 90 87 111"
A.Home.State = "Italy"
A.Home.Town = "Pavia"
A.Home.Street = "Corso Napoleone"
A.Home.CivicNumber = "96/B"
A.Home.Cap = "27010" 


<< Precedente Prossimo >>
A proposito dell'autore

Programmatore e analista .NET 2005/2008/2010 (in particolare C# e VB.NET), anche nell'implementazione Mono per Linux. Conoscenze approfondite di Pascal, PHP, XML, HTML 4.01/5, CSS 2.1/3, Javascript (e jQuery). Conoscenze buone di C, LUA, GML, Ruby, XNA, AJAX e Assembly 68000. Competenze basilari di C++, SQL, Hlsl, Java.