Condividi tramite


Istruzione For Each...Next (Visual Basic)

Consentono di ripetere un gruppo di istruzioni per ciascun elemento di una raccolta.

For Each element [ As datatype ] In group
    [ statements ]
    [ Continue For ]
    [ statements ]
    [ Exit For ]
    [ statements ]
Next [ element ]

Parti

Termine

Definizione

element

Obbligatorio nell'istruzione For Each. Facoltativa nell'istruzione Next. Variabile. Utilizzata per scorrere gli elementi della raccolta.

datatype

Obbligatorio se element non è già dichiarato. Tipo di dati di element.

group

Necessario. Una variabile con un tipo che è un tipo di raccolta o un oggetto. Fa riferimento alla raccolta sulla quale devono essere ripetute le statements.

statements

Opzionale. Una o più istruzioni tra For Each e Next che vengono eseguite su ciascun elemento incluso in group.

Continue For

Opzionale. Trasferisce il controllo all'inizio del ciclo For Each.

Exit For

Opzionale. Trasferisce il controllo all'esterno del ciclo For Each.

Next

Necessario. Termina la definizione del ciclo For Each.

Esempio semplice

Utilizzare un ciclo For Each...Next quando si desidera ripetere un set di istruzioni per ciascun elemento di una raccolta o di una matrice.

Suggerimento

Con l'istruzione Istruzione For...Next (Visual Basic) è consigliabile associare ciascuna iterazione di un ciclo a una variabile di controllo e definire i valori iniziale e finale di tale variabile.Tuttavia, quando si utilizzano di una raccolta, il concetto di valori iniziali e finali non è significativo e non si conosce il numero di elementi della raccolta dispone.In questo tipo di evento, un ciclo di For Each…Next è spesso una scelta migliore.

Nell'esempio seguente, l'istruzione di For Each…Next scorrere tutti gli elementi di una raccolta di elenchi.

' Create a list of strings by using a 
' collection initializer. 
Dim lst As New List(Of String) _
    From {"abc", "def", "ghi"}

' Iterate through the list. 
For Each item As String In lst
    Debug.Write(item & " ")
Next
Debug.WriteLine("")
'Output: abc def ghi

Per ulteriori esempi, vedere Raccolte (C# e Visual Basic) e Matrici in Visual Basic.

Cicli annidati

È possibile annidare cicli For Each inserendo un ciclo all'interno dell'altro.

Nell'esempio seguente vengono illustrate delle strutture For Each…Next annidate.

' Create lists of numbers and letters 
' by using array initializers. 
Dim numbers() As Integer = {1, 4, 7}
Dim letters() As String = {"a", "b", "c"}

' Iterate through the list by using nested loops. 
For Each number As Integer In numbers
    For Each letter As String In letters
        Debug.Write(number.ToString & letter & " ")
    Next 
Next
Debug.WriteLine("")
'Output: 1a 1b 1c 4a 4b 4c 7a 7b 7c 

Quando annidate cicli, ogni ciclo deve avere una variabile univoca di element.

È inoltre possibile annidare strutture di controllo di tipo diverso inserendole una all'interno dell'altra. Per ulteriori informazioni, vedere Strutture di controllo annidate (Visual Basic).

L'uscita per e continua per

L'esecuzione di cause dell'istruzione Per uscita per uscire dal ciclo di For…Next e il trasferisce il controllo all'istruzione che segue l'istruzione di Next.

Tramite l'istruzione Continue For il controllo viene trasferito immediatamente alla successiva iterazione del ciclo. Per ulteriori informazioni, vedere Istruzione Continue (Visual Basic).

Nell'esempio riportato di seguito viene illustrato come utilizzare le istruzioni Continue For e Exit For.

Dim numberSeq() As Integer =
    {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

For Each number As Integer In numberSeq
    ' If number is between 5 and 7, continue 
    ' with the next iteration. 
    If number >= 5 And number <= 8 Then 
        Continue For 
    End If 

    ' Display the number.
    Debug.Write(number.ToString & " ")

    ' If number is 10, exit the loop. 
    If number = 10 Then 
        Exit For 
    End If 
Next
Debug.WriteLine("")
' Output: 1 2 3 4 9 10

È possibile inserire un numero illimitato di istruzioni Exit For in un ciclo For Each. Se utilizzata all'interno di cicli For Each annidati, l'istruzione Exit For consente l'uscita dal ciclo più interno e il trasferimento del controllo al livello di annidamento successivo superiore.

L'istruzione Exit For spesso viene utilizzata dopo la valutazione di una determinata condizione, ad esempio in una struttura If...Then...Else. Si potrebbe decidere di utilizzare il controllo Exit For per le seguenti condizioni:

  • La continuazione dell'iterazione non è necessaria oppure è impossibile. Tale condizione potrebbe essere causata da un valore erroneo o da una richiesta di terminazione.

  • Eccezione intercettata in un blocco Try...Catch...Finally. È possibile utilizzare Exit For alla fine del blocco Finally.

  • È presente un ciclo infinito, vale a dire un ciclo che può essere eseguito molte volte oppure all'infinito. Se si rileva una simile condizione, è possibile utilizzare Exit For per interrompere l'esecuzione del ciclo. Per ulteriori informazioni, vedere Istruzione Do...Loop (Visual Basic).

Iteratori

Utilizzare un iteratore per eseguire un'iterazione personalizzata in una raccolta. Un iteratore può essere una funzione o una funzione di accesso di Get. Utilizza un'istruzione di Yield per restituire ogni elemento della raccolta uno alla volta.

Chiama un iteratore utilizzando un'istruzione di For Each...Next. Ogni iterazione del ciclo For Each chiama l'iteratore. Quando un'istruzione di Yield viene raggiunto l'iteratore, l'espressione nell'istruzione di Yield e viene restituita la posizione corrente nel codice vengono mantenute. Alla successiva chiamata dell'iteratore, l'esecuzione verrà riavviata a partire da quella posizione.

Nell'esempio viene utilizzata una funzione di iteratore. La funzione di iteratore ha un'istruzione di Yield presente in un ciclo di Per… next. Nel metodo di ListEvenNumbers, ogni iterazione del corpo dell'istruzione For Each crea una chiamata alla funzione di iteratore, che consente alla successiva istruzione di Yield.

Public Sub ListEvenNumbers()
    For Each number As Integer In EvenSequence(5, 18)
        Debug.Write(number & " ")
    Next
    Debug.WriteLine("")
    ' Output: 6 8 10 12 14 16 18 
End Sub 

Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As System.Collections.Generic.IEnumerable(Of Integer)

    ' Yield even numbers in the range. 
    For number = firstNumber To lastNumber
        If number Mod 2 = 0 Then
            Yield number
        End If 
    Next 
End Function

Per ulteriori informazioni, vedere Iteratori (C# e Visual Basic), Istruzione Yield (Visual Basic) e Iteratore (Visual Basic).

Implementazione tecnica

Quando un'istruzione di For Each…Next viene eseguita, Visual Basic valuta la raccolta solo una volta, prima che inizi il ciclo. Se il blocco di istruzioni modifica element o group, tali modifiche non influiscono sull'iterazione del ciclo.

Dopo che tutti gli elementi della raccolta sono stati assegnati a element, il ciclo For Each si arresta e il controllo passa all'istruzione successiva all'istruzione Next.

Se element non è stato dichiarato fuori del ciclo, è necessario dichiararlo nell'istruzione di For Each. È possibile dichiarare in modo esplicito il tipo dell'oggetto element tramite un'istruzione As oppure è possibile basarsi sull'inferenza dei tipi per assegnare il tipo. In entrambi i casi, l'ambito dell'oggetto element è il corpo del ciclo. Non è tuttavia possibile dichiarare element all'interno e all'esterno del ciclo.

Se lo si desidera, è possibile specificare element nell'istruzione Next. Ciò consente di migliorare la leggibilità del programma, soprattutto se i cicli For Each sono annidati. È necessario specificare la stessa variabile presente nell'istruzione For Each corrispondente.

Si potrebbe decidere di evitare di modificare il valore di element all'interno di un ciclo. Tale operazione può rendere più difficile la lettura e il debug del codice. Modificare il valore di group non influisce sulla raccolta o i relativi elementi, che siano stati determinati quando il ciclo viene immesso.

Quando si cicli di annidamento, se un'istruzione di Next di un livello di annidamento esterno viene visualizzato prima di Next di un livello interno, viene segnalato un errore. Tuttavia, il compilatore può rilevare questo errore di sovrapposizione solo se si specifica element in ogni istruzione Next.

Se il codice dipende da scorrere una raccolta in un determinato ordine, un ciclo di For Each…Next non è la scelta ideale, a meno che non si conosca che le caratteristiche dell'oggetto enumerator essa esposte. L'ordine di scorrimento non è determinato da Visual Basic, ma con il metodo di MoveNext dell'oggetto enumerator. Pertanto, potrebbe non essere possibile prevedere quale elemento della raccolta verrà restituito per primo in element o quale sarà l'elemento restituito dopo un determinato elemento. È possibile ottenere risultati più affidabili utilizzando un struttura di ciclo diversa, ad esempio For...Next o Do...Loop..

Per i dati di tipo element è necessario specificare un tipo di dati in cui possa essere convertito il tipo di dati degli elementi di group.

Il tipo di dati di group deve essere un tipo di riferimento che fa riferimento a una raccolta o a una matrice che è enumerabile. Nella maggior parte dei casi, ciò significa che group fa riferimento a un oggetto che implementa l'interfaccia IEnumerable dello spazio dei nomi System.Collections oppure l'interfaccia IEnumerable dello spazio dei nomi System.Collections.Generic. System.Collections.IEnumerable definisce il metodo GetEnumerator, il quale restituisce un oggetto enumeratore per la raccolta. L'oggetto enumeratore implementa l'interfaccia System.Collections.IEnumerator dello spazio dei nomi System.Collections ed espone la proprietà Current e i metodi Reset e MoveNext che verranno utilizzati per scorrere la raccolta.

Conversioni di restrizione

Quando l'oggetto Option Strict è impostato su On, le conversioni verso un tipo di dati più piccolo causano solitamente errori del compilatore. In un'istruzione For Each, tuttavia, le conversioni dagli elementi nell'oggetto group all'oggetto element vengono valutate ed eseguite in fase di esecuzione e gli errori del compilatore causati da conversioni verso un tipo di dati più piccolo vengono eliminati.

Nell'esempio seguente, l'assegnazione di m come valore iniziale per n non viene compilato quando Option Strict si trova in quanto la conversione di Long a Integer è una conversione verso un tipo di dati più piccolo. Nell'istruzione For Each, tuttavia, non viene segnalato alcun errore del compilatore, sebbene per l'assegnazione a number sia richiesta la stessa conversione da Long a Integer. Nell'istruzione For Each in cui è contenuto un numero grande, si verifica un errore di run-time quando il metodo ToInteger viene applicato al numero grande.

Option Strict On 

Module Module1
    Sub Main()
        ' The assignment of m to n causes a compiler error when  
        ' Option Strict is on. 
        Dim m As Long = 987
        'Dim n As Integer = m 

        ' The For Each loop requires the same conversion but 
        ' causes no errors, even when Option Strict is on. 
        For Each number As Integer In New Long() {45, 3, 987}
            Console.Write(number & " ")
        Next
        Console.WriteLine()
        ' Output: 45 3 987 

        ' Here a run-time error is raised because 9876543210 
        ' is too large for type Integer. 
        'For Each number As Integer In New Long() {45, 3, 9876543210} 
        '    Console.Write(number & " ") 
        'Next

        Console.ReadKey()
    End Sub 
End Module

Chiamate IEnumerator

All'avvio dell'esecuzione di un ciclo For Each...Next, in Visual Basic viene verificato che group faccia riferimento a un oggetto Collection valido. In caso negativo, verrà generata un'eccezione. In caso affermativo, vengono chiamati il metodo MoveNext e la proprietà Current dell'oggetto enumeratore per restituire il primo elemento. Se tramite il metodo MoveNext viene indicato che non sono disponibili altri elementi, vale a dire che la raccolta è vuota, il ciclo For Each viene arrestato e il controllo passa all'istruzione successiva all'istruzione Next. Altrimenti, element viene impostato sul primo elemento, quindi viene eseguito il blocco di istruzioni.

Ogni volta che rileva l'istruzione Next, Visual Basic torna all'istruzione For Each. Vengono chiamati nuovamente il metodo MoveNext e la proprietà Current per restituire l'elemento successivo, quindi, in base al risultato, viene eseguito il blocco oppure viene arrestato il ciclo. Questo processo continua finché il metodo MoveNext indica che non esistono altri elementi oppure finché non viene rilevata un'istruzione Exit For.

Modifica della raccolta. L'oggetto restituito da enumeratore GetEnumerator in genere non consente di modificare la libreria aggiunta, eliminazione, sostituendo, o riordinando elementi. Se si modifica la raccolta dopo aver iniziato un ciclo For Each...Next, l'oggetto enumeratore diventa non valido e con il tentativo successivo di accedere a un elemento si causa un'eccezione InvalidOperationException.

Tuttavia, questo blocco di modifica non è determinato da Visual Basic, ma dall'implementazione dell'interfaccia di IEnumerable. È possibile implementare IEnumerable in modo da consentire le modifiche durante l'iterazione. Se si intende eseguire tale modifica dinamica, accertarsi di avere un'adeguata conoscenza delle caratteristiche dell'implementazione di IEnumerable nella raccolta utilizzata.

Modifica degli elementi di una raccolta. La proprietà Current dell'oggetto enumeratore è ReadOnly (Visual Basic) e restituisce una copia locale di ogni elemento della raccolta. Pertanto non sarà possibile modificare gli elementi stessi in un ciclo For Each...Next. Qualsiasi modifica apportata alle ha effetto solo sulla copia locale di Current e non vengono riflessi nella raccolta sottostante. Se tuttavia un elemento è un tipo di riferimento, sarà possibile modificare i membri dell'istanza a cui esso punta. Nell'esempio seguente viene modificato il membro di BackColor di ogni elemento di thisControl. Non è possibile, tuttavia, modificare thisControl stesso.

Sub lightBlueBackground(ByVal thisForm As System.Windows.Forms.Form)
    For Each thisControl As System.Windows.Forms.Control In thisForm.Controls
        thisControl.BackColor = System.Drawing.Color.LightBlue
    Next thisControl
End Sub

Nell'esempio precedente è possibile modificare il membro BackColor di ciascun elemento thisControl ma non è possibile modificare l'elemento thisControl stesso.

Attraversamento di matrici. Poiché la classe Array implementa l'interfaccia IEnumerable, tutte le matrici espongono il metodo GetEnumerator. Pertanto è possibile scorrere una matrice con un ciclo For Each...Next. Tuttavia, gli elementi della matrice possono essere solo letti. Non è possibile modificarli.

Esempio

Nell'esempio seguente vengono elencate tutte le cartelle nella directory C:\ tramite la classe DirectoryInfo.

Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
    Debug.WriteLine(dir.Name)
Next

Nell'esempio seguente viene illustrata una routine di ordinamento della raccolta. Le istanze di base di esempio Car classe archiviate in List. La classe Car implementa l'interfaccia IComparable, che richiede che il metodo CompareTo venga implementato.

Ogni chiamata al metodo di CompareTo effettua un'unica confronto utilizzato per l'ordinamento. Il codice utente nel metodo CompareTo restituisce un valore per ogni confronto dell'oggetto corrente con un altro oggetto. Il valore restituito è minore di zero se l'oggetto corrente è inferiore all'altro oggetto, maggiore di zero se l'oggetto corrente è superiore all'altro oggetto e zero se sono uguali. Ciò consente di definire in codifica i criteri per maggiore di, minore di e il segno di uguale.

Nel metodo ListCars, l'istruzione cars.Sort() ordina l'elenco. Questa chiamata al metodo Sort List modo il metodo CompareTo venga chiamata automaticamente per gli oggetti Car in List.

Public Sub ListCars()

    ' Create some new cars. 
    Dim cars As New List(Of Car) From
    {
        New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
        New Car With {.Name = "car2", .Color = "red", .Speed = 50},
        New Car With {.Name = "car3", .Color = "green", .Speed = 10},
        New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
        New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
        New Car With {.Name = "car6", .Color = "red", .Speed = 60},
        New Car With {.Name = "car7", .Color = "green", .Speed = 50}
    }

    ' Sort the cars by color alphabetically, and then by speed 
    ' in descending order.
    cars.Sort()

    ' View all of the cars. 
    For Each thisCar As Car In cars
        Debug.Write(thisCar.Color.PadRight(5) & " ")
        Debug.Write(thisCar.Speed.ToString & " ")
        Debug.Write(thisCar.Name)
        Debug.WriteLine("")
    Next 

    ' Output: 
    '  blue  50 car4 
    '  blue  30 car5 
    '  blue  20 car1 
    '  green 50 car7 
    '  green 10 car3 
    '  red   60 car6 
    '  red   50 car2 
End Sub 

Public Class Car
    Implements IComparable(Of Car)

    Public Property Name As String 
    Public Property Speed As Integer 
    Public Property Color As String 

    Public Function CompareTo(ByVal other As Car) As Integer _
        Implements System.IComparable(Of Car).CompareTo
        ' A call to this method makes a single comparison that is 
        ' used for sorting. 

        ' Determine the relative order of the objects being compared. 
        ' Sort by color alphabetically, and then by speed in 
        ' descending order. 

        ' Compare the colors. 
        Dim compare As Integer
        compare = String.Compare(Me.Color, other.Color, True)

        ' If the colors are the same, compare the speeds. 
        If compare = 0 Then
            compare = Me.Speed.CompareTo(other.Speed)

            ' Use descending order for speed.
            compare = -compare
        End If 

        Return compare
    End Function 
End Class

Vedere anche

Riferimenti

Istruzione For...Next (Visual Basic)

Istruzione While...End While (Visual Basic)

Istruzione Do...Loop (Visual Basic)

Concetti

Strutture di ciclo (Visual Basic)

Conversioni di ampliamento e restrizione (Visual Basic)

Inizializzatori di oggetto: tipi denominati e tipi anonimi (Visual Basic)

Inizializzatori di raccolte (Visual Basic)

Altre risorse

Raccolte (C# e Visual Basic)

Matrici in Visual Basic