Istruzione For Each...Next (Visual Basic)
Ripete un gruppo di istruzioni per ogni elemento di una raccolta.
Sintassi
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 . Facoltativo nell'istruzione Next . Variabile. Utilizzato per scorrere gli elementi della raccolta. |
datatype |
Facoltativo se Option Infer è attivato (impostazione predefinita) o element è già dichiarato; obbligatorio se Option Infer è disattivato e element non è già dichiarato. Tipo di dati del parametro element . |
group |
Obbligatorio. Variabile con un tipo che è un tipo di raccolta o Object. Fa riferimento alla raccolta su cui deve essere ripetuto l'oggetto statements . |
statements |
Facoltativa. Una o più istruzioni tra For Each e Next eseguite su ogni elemento in group . |
Continue For |
Facoltativa. Trasferisce il controllo all'inizio del For Each ciclo. |
Exit For |
Facoltativa. Trasferisce il controllo fuori dal For Each ciclo. |
Next |
Obbligatorio. Termina la definizione del For Each ciclo. |
Esempio semplice
Usare un For Each
ciclo ...Next
quando si desidera ripetere un set di istruzioni per ogni elemento di una raccolta o di una matrice.
Suggerimento
Un for... Next Statement funziona bene quando è possibile associare ogni iterazione di un ciclo a una variabile di controllo e determinare i valori iniziali e finali della variabile. Tuttavia, quando si usa una raccolta, il concetto di valori iniziali e finali non è significativo e non si conosce necessariamente il numero di elementi presenti nella raccolta. In questo tipo di caso, un For Each
ciclo ...Next
è spesso una scelta migliore.
Nell'esempio seguente, ...For Each
Next
l'istruzione scorre tutti gli elementi di un insieme List.
' 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 altri esempi, vedere Raccolte e matrici.
Nested Loops
È possibile annidare For Each
i cicli inserendo un ciclo all'interno di un altro.
Nell'esempio seguente viene illustrato l'annidamento For Each
...Next
Strutture.
' 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 si annidano cicli, ogni ciclo deve avere una variabile univoca element
.
È anche possibile annidare diversi tipi di strutture di controllo tra loro. Per altre informazioni, vedere Strutture di controllo annidate.
Esci per e continua per
L'istruzione Exit For causa l'uscita dall'istruzione For
...Next
loop e trasferisce il controllo all'istruzione che segue l'istruzione Next
.
L'istruzione Continue For
trasferisce immediatamente il controllo all'iterazione successiva del ciclo. Per altre informazioni, vedere Istruzione Continue.
Nell'esempio seguente viene illustrato come usare le Continue For
istruzioni 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 8, 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 qualsiasi di Exit For
istruzioni in un For Each
ciclo. Se usato all'interno di cicli annidati For Each
, Exit For
causa l'uscita dall'esecuzione del ciclo più interno e trasferisce il controllo al livello superiore successivo di annidamento.
Exit For
viene spesso usato dopo una valutazione di alcune condizioni, ad esempio in un If
...Then
...Else
Struttura. È possibile usare Exit For
per le condizioni seguenti:
Continuare a eseguire l'iterazione non è necessario o impossibile. Ciò potrebbe essere causato da un valore errato o da una richiesta di terminazione.
Un'eccezione viene intercettata in un
Try
...Catch
...Finally
. È possibile usareExit For
alla fine delFinally
blocco.Esiste un ciclo infinito, ovvero un ciclo che può essere eseguito un numero elevato o persino infinito di volte. Se si rileva una condizione di questo tipo, è possibile usare per eseguire
Exit For
l'escape del ciclo. Per altre informazioni, vedere Do... Istruzione Loop.
Iterators
Si usa un iteratore per eseguire un'iterazione personalizzata su una raccolta. Un iteratore può essere una funzione o una Get
funzione di accesso. Usa un'istruzione Yield
per restituire ogni elemento della raccolta uno alla volta.
Per chiamare un iteratore, usare un'istruzione For Each...Next
. Ogni iterazione del ciclo For Each
chiama l'iteratore. Quando viene raggiunta un'istruzione Yield
nell'iteratore, viene restituita l'espressione nell'istruzione Yield
e viene mantenuta la posizione corrente nel codice. L'esecuzione viene ripresa a partire da quella posizione la volta successiva che viene chiamato l'iteratore.
Nell'esempio seguente viene usata una funzione iteratore. La funzione iteratore ha un'istruzione Yield
che si trova all'interno di un for... Ciclo successivo . ListEvenNumbers
Nel metodo ogni iterazione del corpo dell'istruzione For Each
crea una chiamata alla funzione iteratore, che procede all'istruzione successivaYield
.
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 altre informazioni, vedere Iteratori, istruzione Yield e Iterator.
Implementazione tecnica
Quando un For Each
...Next
l'istruzione viene eseguita, Visual Basic valuta la raccolta una sola volta, prima dell'avvio del ciclo. Se l'istruzione blocca le modifiche element
o group
, queste modifiche non influiscono sull'iterazione del ciclo.
Quando tutti gli elementi della raccolta sono stati assegnati successivamente a element
, il For Each
ciclo si arresta e il controllo passa all'istruzione che segue l'istruzione Next
.
Se Option Infer è attivato (impostazione predefinita), il compilatore Visual Basic può dedurre il tipo di dati di element
. Se è disattivato e element
non è stato dichiarato all'esterno del ciclo, è necessario dichiararlo nell'istruzione For Each
. Per dichiarare il tipo di dati in element
modo esplicito, usare una As
clausola . A meno che il tipo di dati dell'elemento non sia definito al di fuori del For Each
costrutto ...Next
, l'ambito è il corpo del ciclo. Si noti che non è possibile dichiarare element
sia all'esterno che all'interno del ciclo.
Facoltativamente, è possibile specificare element
nell'istruzione Next
. Ciò migliora la leggibilità del programma, soprattutto se sono presenti cicli annidati For Each
. È necessario specificare la stessa variabile di quella visualizzata nell'istruzione corrispondente For Each
.
È possibile evitare di modificare il valore di all'interno di element
un ciclo. Questa operazione può rendere più difficile leggere ed eseguire il debug del codice. La modifica del valore di group
non influisce sulla raccolta o sui relativi elementi, che sono stati determinati quando il ciclo è stato immesso per la prima volta.
Quando si annida cicli, se viene rilevata un'istruzione Next
di un livello di annidamento esterno prima Next
di di un livello interno, il compilatore segnala un errore. Tuttavia, il compilatore può rilevare questo errore sovrapposto solo se si specifica element
in ogni Next
istruzione.
Se il codice dipende dall'attraversamento di una raccolta in un ordine specifico, un For Each
ciclo ...Next
non è la scelta migliore, a meno che non si conoscano le caratteristiche dell'oggetto enumeratore esposto dall'insieme. L'ordine di attraversamento non è determinato da Visual Basic, ma dal MoveNext metodo dell'oggetto enumeratore. Pertanto, potrebbe non essere possibile stimare quale elemento della raccolta è il primo a essere restituito in element
o che è l'elemento successivo a essere restituito dopo un determinato elemento. È possibile ottenere risultati più affidabili usando una struttura di ciclo diversa, ad esempio For
...Next
o Do
...Loop
.
Il runtime deve essere in grado di convertire gli elementi in group
element
. L'istruzione [Option Strict
] controlla se sono consentite conversioni sia di tipo widening che di tipo narrowing (Option Strict
è disattivato, il relativo valore predefinito) o se sono consentite solo conversioni di tipo widening (Option Strict
è attivato). Per altre informazioni, vedere Conversioni di tipo narrowing.
Il tipo di dati di group
deve essere un tipo riferimento che fa riferimento a una raccolta o a una matrice che è enumerabile. In genere ciò significa che group
fa riferimento a un oggetto che implementa l'interfaccia IEnumerable dello System.Collections
spazio dei nomi o l'interfaccia IEnumerable<T> dello System.Collections.Generic
spazio dei nomi. System.Collections.IEnumerable
definisce il GetEnumerator metodo , che restituisce un oggetto enumeratore per la raccolta. L'oggetto enumeratore implementa l'interfaccia System.Collections.IEnumerator
dello System.Collections
spazio dei nomi ed espone la Current proprietà e i Reset metodi e MoveNext . Visual Basic usa questi oggetti per attraversare la raccolta.
conversioni verso un tipo di dati più piccolo
Quando Option Strict
è impostato su On
, le conversioni di restringezione causano normalmente errori del compilatore. In un'istruzioneFor Each
, tuttavia, le conversioni degli elementi in in element
group
vengono valutate ed eseguite in fase di esecuzione e gli errori del compilatore causati da conversioni limitate vengono eliminati.
Nell'esempio seguente l'assegnazione di m
come valore iniziale per n
non viene compilata quando Option Strict
è attiva perché la conversione di un oggetto in un Long
Integer
oggetto è una conversione ridotta. Nell'istruzione, tuttavia, non viene segnalato alcun errore del For Each
compilatore, anche se l'assegnazione per number
richiedere la stessa conversione da Long
a Integer
. Nell'istruzione For Each
contenente un numero elevato si verifica un errore di runtime quando ToInteger viene applicato al numero elevato.
Option Strict On
Imports System
Module Program
Sub Main(args As String())
' 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
End Sub
End Module
Chiamate di IEnumerator
Quando l'esecuzione di un ciclo ...Next
viene avviata, Visual Basic verifica che group
si riferisce a un For Each
oggetto di raccolta valido. In caso contrario, genera un'eccezione. In caso contrario, chiama il metodo e la MoveNextCurrent proprietà dell'oggetto enumeratore per restituire il primo elemento. Se MoveNext
indica che non esiste alcun elemento successivo, ovvero se la raccolta è vuota, il For Each
ciclo si arresta e il controllo passa all'istruzione che segue l'istruzione Next
. In caso contrario, Visual Basic imposta element
sul primo elemento ed esegue il blocco dell'istruzione.
Ogni volta che Visual Basic rileva l'istruzione, viene restituita all'istruzione Next
For Each
. MoveNext
Chiama di nuovo e Current
restituisce l'elemento successivo e di nuovo esegue il blocco o arresta il ciclo a seconda del risultato. Questo processo continua fino a quando MoveNext
non è presente alcun elemento successivo o viene rilevata un'istruzione Exit For
.
Modifica della raccolta. L'oggetto enumeratore restituito normalmente GetEnumerator non consente di modificare la raccolta aggiungendo, eliminando, sostituendo o riordinando eventuali elementi. Se si modifica la raccolta dopo aver avviato un For Each
ciclo ...Next
, l'oggetto enumeratore diventa non valido e il successivo tentativo di accesso a un elemento causa un'eccezione InvalidOperationException .
Tuttavia, questo blocco di modifiche non è determinato da Visual Basic, ma piuttosto dall'implementazione dell'interfaccia IEnumerable . È possibile implementare IEnumerable
in modo da consentire la modifica durante l'iterazione. Se si sta valutando questa modifica dinamica, assicurarsi di comprendere le caratteristiche dell'implementazione IEnumerable
nella raccolta in uso.
Modifica degli elementi della raccolta. La Current proprietà dell'oggetto enumeratore è ReadOnly e restituisce una copia locale di ogni elemento della raccolta. Ciò significa che non è possibile modificare gli elementi stessi in un For Each
ciclo ...Next
. Tutte le modifiche apportate influiscono solo sulla copia locale da Current
e non vengono riflesse nuovamente nella raccolta sottostante. Tuttavia, se un elemento è un tipo di riferimento, è possibile modificare i membri dell'istanza in cui punta. Nell'esempio seguente viene modificato il BackColor
membro di ogni thisControl
elemento. Non è tuttavia possibile modificare thisControl
se stesso.
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
L'esempio precedente può modificare il BackColor
membro di ogni thisControl
elemento, anche se non può modificarlo thisControl
.
Attraversamento di matrici. Poiché la Array classe implementa l'interfaccia IEnumerable , tutte le matrici espongono il GetEnumerator metodo. Ciò significa che è possibile scorrere una matrice con un For Each
ciclo ...Next
. Tuttavia, è possibile leggere solo gli elementi della matrice. Non è possibile modificarli.
Esempio 1
Nell'esempio seguente vengono elencate tutte le cartelle in C:\ directory usando la DirectoryInfo classe .
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
Esempio 2
L'esempio seguente illustra una procedura per ordinare una raccolta. L'esempio ordina istanze di una Car
classe archiviata in un List<T>oggetto . La classe Car
implementa l'interfaccia IComparable<T>, che richiede l'implementazione del metodo CompareTo.
Ogni chiamata al CompareTo metodo esegue un singolo confronto usato per l'ordinamento. Il codice scritto dall'utente presente 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. In questo modo è possibile definire nel codice i criteri di maggiore, minore e uguale.
Nel metodo ListCars
l'istruzione cars.Sort()
ordina l'elenco. Questa chiamata al metodo Sort di List<T> determina la chiamata automatica al metodo CompareTo
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
Vedi anche
Commenti e suggerimenti
Invia e visualizza il feedback per