Istruzione For Each...Next (Visual Basic)

Consentono di ripetere un gruppo di istruzioni per ciascun elemento di un insieme.

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

Parti

Argomento

Definizione

element

Obbligatorio nell'istruzione For Each. Facoltativa nell'istruzione Next. Variabile. Utilizzata per scorrere gli elementi dell'insieme.

datatype

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

group

Obbligatoria. Variabile oggetto. Fa riferimento all'insieme sul quale devono essere ripetute le statements.

statements

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

Continue For

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

Exit For

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

Next

Obbligatoria. Termina la definizione del ciclo For Each.

Note

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

In Visual Basic l'insieme viene restituito una volta sola prima dell'avvio del ciclo. Se nel blocco di istruzioni element o group cambiano, le modifiche non avranno alcun effetto sulla ripetizione del ciclo.

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

Se la variabile element non è stata dichiarata all'esterno del ciclo, è necessario dichiararla nell'istruzione 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. La modifica del valore del parametro group non ha impatto sull'insieme e sui relativi elementi, i quali sono stati definiti quando il ciclo è stato avviato per la prima volta.

SuggerimentoSuggerimento

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. Con un insieme, invece, non è necessario specificare i valori iniziale e finale e nemmeno conoscere il numero di elementi disponibili. In questo caso, è consigliabile utilizzare un ciclo For Each...Next.

Se il codice dipende dall'attraversamento di un insieme in base a un ordine particolare, un ciclo For Each...Next non rappresenta la scelta ottimale se non si conoscono le caratteristiche dell'oggetto enumeratore esposto dall'insieme. L'ordine di scorrimento non è determinato da Visual Basic, ma dal metodo MoveNext dell'oggetto enumeratore. Pertanto, potrebbe non essere possibile prevedere quale elemento dell'insieme 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..

Cicli annidati

È possibile annidare cicli For Each inserendo un ciclo all'interno dell'altro. ma dotando ciascuno di essi di una variabile element univoca.

È 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).

Se viene rilevata un'istruzione Next di un livello di annidamento esterno prima dell'istruzione Next di un livello interno, il compilatore restituisce un errore. Tuttavia, il compilatore può rilevare questo errore di sovrapposizione solo se si specifica element in ogni istruzione Next.

Exit For

Mediante l'istruzione Exit For viene causata l'uscita dell'esecuzione dal ciclo For…Next e il controllo viene trasferito all'istruzione successiva all'istruzione Next.

È 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).

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

Tipi di dati

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 corrispondere a un tipo di riferimento che fa riferimento a un insieme o a una matrice 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<T> dello spazio dei nomi System.Collections.Generic. System.Collections.IEnumerable definisce il metodo GetEnumerator, il quale restituisce un oggetto enumeratore per l'insieme. 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 l'insieme.

Gli elementi di group sono generalmente di tipo Object, tuttavia possono essere disponibili anche tipi di dati runtime.

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 consente la compilazione se l'oggetto Option Strict è attivo in quanto la conversione di un valore Long in un valore 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 insieme 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 l'insieme è vuoto, 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.

Modifiche

Modifica dell'insieme. L'oggetto enumeratore restituito da GetEnumerator in genere non consente di modificare l'insieme mediante l'aggiunta, l'eliminazione, la sostituzione o il riordino di elementi. Se si modifica l'insieme 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, il blocco delle modifiche non è determinato da Visual Basic, ma piuttosto dall'implementazione dell'interfaccia 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 nell'insieme utilizzato.

Modifica degli elementi di un insieme. La proprietà Current dell'oggetto enumeratore è ReadOnly (Visual Basic) e restituisce una copia locale di ogni elemento dell'insieme. Pertanto non sarà possibile modificare gli elementi stessi in un ciclo For Each...Next. Le eventuali modifiche apportate influenzano solo la copia locale di Current e non si riflettono nell'insieme sottostante. Se tuttavia un elemento è un tipo di riferimento, sarà possibile modificare i membri dell'istanza a cui esso punta. Nell'esempio riportato di seguito viene illustrata questa situazione.

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. Per informazioni generali, vedere Procedura: eseguire diverse istruzioni per ciascun elemento in un insieme o in una matrice (Visual Basic).

Esempio

Nell'esempio riportato di seguito viene illustrato come utilizzare l'istruzione For Each…Next.

' 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

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 

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

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 mostrato come ordinare un insieme utilizzando l'interfaccia IComparable.

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
        ' Determine the relative order of the objects being compared.
        ' This is used to 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

Nell'esempio seguente è inclusa una classe di insiemi personalizzata che dispone di un enumeratore personalizzato.

Public Sub ListColors()
    Dim colors As New AllColors()

    For Each theColor As Color In colors
        Debug.Write(theColor.Name & " ")
    Next
    Debug.WriteLine("")
    ' Output: red blue green
End Sub

' Collection class.
Public Class AllColors
    Implements System.Collections.IEnumerable

    Private _colors() As Color =
    {
        New Color With {.Name = "red"},
        New Color With {.Name = "blue"},
        New Color With {.Name = "green"}
    }

    Public Function GetEnumerator() As System.Collections.IEnumerator _
        Implements System.Collections.IEnumerable.GetEnumerator

        Return New ColorEnumerator(_colors)

        ' Instead of creating a using a custom enumerator, you could
        ' use the GetEnumerator of the array.
        'Return _colors.GetEnumerator
    End Function

    ' Custom enumerator.
    Private Class ColorEnumerator
        Implements System.Collections.IEnumerator

        Private _colors() As Color
        Private _position As Integer = -1

        Public Sub New(ByVal colors() As Color)
            _colors = colors
        End Sub

        Public ReadOnly Property Current() As Object Implements System.Collections.IEnumerator.Current
            Get
                Return _colors(_position)
            End Get
        End Property

        Public Function MoveNext() As Boolean Implements System.Collections.IEnumerator.MoveNext
            _position += 1
            Return (_position < _colors.Length)
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            _position = -1
        End Sub
    End Class
End Class

' Element class.
Public Class Color
    Public Property Name As String
End Class

Vedere anche

Attività

Procedura: eseguire diverse istruzioni per ciascun elemento in un insieme o in una matrice (Visual Basic)

Riferimenti

Istruzione For...Next (Visual Basic)

Istruzione While...End While (Visual Basic)

Istruzione Do...Loop (Visual Basic)

Concetti

Strutture di ciclo (Visual Basic)

Insiemi in Visual Basic

Conversioni di ampliamento e restrizione (Visual Basic)

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

Cenni preliminari sugli inizializzatori di insieme (Visual Basic)

Matrici in Visual Basic

Cronologia delle modifiche

Data

Cronologia

Motivo

Dicembre 2010

La sezione Note è stata riorganizzata e sono stati aggiunti degli esempi.

Miglioramento delle informazioni.