Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
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 |
Richiesto nell'istruzione For Each. Facoltativo nell'istruzione Next . Variabile. Utilizzato per scorrere gli elementi della raccolta. |
datatype |
Facoltativo se è attivato (impostazione predefinita) o element è già dichiarato; obbligatorio se Option InferOption Infer è disattivato e element non è già dichiarato. Tipo di dati di 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 |
Opzionale. Una o più istruzioni tra For Each e Next eseguite su ogni elemento in group. |
Continue For |
Opzionale. Trasferisce il controllo all'inizio del For Each ciclo. |
Exit For |
Opzionale. Trasferisce il controllo fuori dal For Each ciclo. |
Next |
Obbligatorio. Termina la definizione del For Each ciclo. |
Esempio semplice
Usare un For Eachciclo ...Next quando si desidera ripetere un set di istruzioni per ogni elemento di una raccolta o di una matrice.
Suggerimento
A For... Istruzione successiva 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 ha a che fare con una raccolta, il concetto di valori iniziali e finali non è significativo e non si conosce necessariamente il numero di elementi della raccolta. In questo tipo di caso, un For Eachciclo ...Next è spesso una scelta migliore.
Nell'esempio seguente il 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.
Cicli annidati
È possibile annidare For Each i cicli inserendo un ciclo all'interno di un altro.
L'esempio seguente illustra 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 da For e Continua con For
L'istruzione Exit For causa l'uscita da 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 l'esecuzione esce dal 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 iterare è inutile o impossibile. Ciò potrebbe essere causato da un valore errato o da una richiesta di terminazione.
Un'eccezione viene rilevata in un
Try...Catch...Finally. È possibile usareExit Foralla fine delFinallyblocco.C'è un ciclo infinito, che è un ciclo che potrebbe eseguire un numero elevato o persino infinito di volte. Se si rileva una condizione di questo tipo, è possibile usare
Exit Forper uscire dal ciclo. Per ulteriori informazioni, vedere Istruzione Do...Loop.
Iteratori
Si usa un iteratore per eseguire un'iterazione personalizzata su una raccolta. Un iteratore può essere una funzione o una funzione di Get 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 For Each ciclo 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 riavviata da tale posizione alla successiva chiamata dell'iteratore.
Nell'esempio seguente viene utilizzata 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 con l'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 Iteratore.
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 di 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 all'esterno del For Eachcostrutto ...Next , il relativo 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 determinato ordine, un For Eachciclo ...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 elemento che è il 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 groupelement. L'istruzione [Option Strict] controlla se sono consentite conversioni di tipo più esteso e di tipo narrow (Option Strict è disattivato, il valore predefinito) o se sono consentite solo conversioni verso un tipo più esteso (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 enumerabile. In genere questo 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 spazio dei System.Collections.Generic nomi.
System.Collections.IEnumerable definisce il GetEnumerator metodo , che restituisce un oggetto enumeratore per l'insieme. 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 ristrette
Quando Option Strict è impostato su On, le conversioni di tipo narrow causano in genere errori del compilatore. In un'istruzioneFor Each, tuttavia, le conversioni dagli elementi in in elementgroup vengono valutate ed eseguite in fase di esecuzione e gli errori del compilatore causati da conversioni di tipo narrowing vengono eliminati.
Nell'esempio seguente, l'assegnazione di m come valore iniziale per n non viene compilata quando Option Strict è attivata perché la conversione di un oggetto in è una conversione verso un LongInteger tipo di dati più piccolo. Nell'istruzione For Each , tuttavia, non viene segnalato alcun errore del compilatore, anche se l'assegnazione a number richiede la stessa conversione da Long a Integer. Nell'istruzione For Each che contiene un numero elevato, si verifica un errore di run-time 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 A IEnumerator
All'avvio dell'esecuzione di un For Eachciclo ...Next Visual Basic verifica che group faccia riferimento a un oggetto raccolta valido. In caso contrario, genera un'eccezione. In caso contrario, chiama il MoveNext metodo e la Current proprietà dell'oggetto enumeratore per restituire il primo elemento. Se MoveNext indica che non è presente 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 il primo elemento ed esegue il blocco di istruzioni.
Ogni volta che Visual Basic rileva l'istruzione Next , viene restituita all'istruzione For Each . Ancora una volta chiama MoveNext e Current per restituire l'elemento successivo e di nuovo esegue il blocco o arresta il ciclo a seconda del risultato. Questo processo continua fino a MoveNext indicare che non è presente alcun elemento successivo o viene rilevata un'istruzione Exit For .
Modifica dell'insieme. L'oggetto enumeratore restituito da GetEnumerator normalmente non consente di modificare la raccolta aggiungendo, eliminando, sostituendo o riordinando gli elementi. Se si modifica la raccolta dopo l'avvio di un For Eachciclo ...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 che consenta la modifica durante l'iterazione. Se si sta valutando l'esecuzione di 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 Eachciclo ...Next . Qualsiasi modifica apportata influisce solo sulla copia locale da Current e non viene riflessa nuovamente nella raccolta sottostante. Tuttavia, se un elemento è un tipo 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ò modificare thisControl se stesso.
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 Eachciclo ...Next . Tuttavia, è possibile leggere solo gli elementi della matrice. Non è possibile modificarli.
Esempio 1
Nell'esempio seguente vengono elencate tutte le cartelle nella directory C:\ 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
Nell'esempio seguente viene illustrata una routine per l'ordinamento di una raccolta. Nell'esempio vengono ordinate istanze di una Car classe archiviate in un oggetto List<T>. La Car classe 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 nel CompareTo metodo restituisce un valore per ogni confronto dell'oggetto corrente con un altro oggetto. Il valore restituito è minore di zero se l'oggetto corrente è minore dell'altro oggetto, maggiore di zero se l'oggetto corrente è maggiore dell'altro oggetto e zero se sono uguali. In questo modo è possibile definire nel codice i criteri per maggiore di, minore di e uguale.
ListCars Nel metodo l'istruzione cars.Sort() ordina l'elenco. Questa chiamata al metodo Sort di List<T> fa sì che il metodo CompareTo venga chiamato 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