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.
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. 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à
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)
Cenni preliminari sugli inizializzatori di insieme (Visual Basic)
Cronologia delle modifiche
Data |
Cronologia |
Motivo |
Dicembre 2010 |
La sezione Note è stata riorganizzata e sono stati aggiunti degli esempi. |
Miglioramento delle informazioni. |