Para cada um... Próxima instrução (Visual Basic)
Repete um grupo de instruções para cada elemento de uma coleção.
Sintaxe
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
Partes
Termo | Definição |
---|---|
element |
Obrigatório na For Each declaração. Opcional na Next declaração. Variável. Usado para iterar através dos elementos da coleção. |
datatype |
Opcional se Option Infer estiver ativado (o padrão) ou element já estiver declarado, obrigatório se Option Infer estiver desativado e element ainda não estiver declarado. O tipo de dados de element . |
group |
Obrigatório. Uma variável com um tipo que é um tipo de coleção ou Object. Refere-se à coleção sobre a qual os statements devem ser repetidos. |
statements |
Opcional. Uma ou mais instruções entre For Each e Next que são executadas em cada item em group . |
Continue For |
Opcional. Transfere o controle para o início do For Each loop. |
Exit For |
Opcional. Transfere o controle para fora do For Each loop. |
Next |
Obrigatório. Encerra a definição do For Each loop. |
Exemplo simples
Use um For Each
loop ...Next
quando quiser repetir um conjunto de instruções para cada elemento de uma coleção ou matriz.
Gorjeta
A para... Next Statement funciona bem quando você pode associar cada iteração de um loop a uma variável de controle e determinar os valores iniciais e finais dessa variável. No entanto, quando você está lidando com uma coleção, o conceito de valores iniciais e finais não é significativo, e você não sabe necessariamente quantos elementos a coleção tem. Neste tipo de caso, um For Each
loop ...Next
é muitas vezes uma escolha melhor.
No exemplo a seguir, o For Each
...Next
itera todos os elementos de uma coleção 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
Para obter mais exemplos, consulte Coleções e matrizes.
Loops aninhados
Você pode aninhar For Each
loops colocando um loop dentro do outro.
O exemplo a seguir demonstra aninhado For Each
...Next
estruturas.
' 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 você aninha loops, cada loop deve ter uma variável exclusiva element
.
Você também pode aninhar diferentes tipos de estruturas de controle entre si. Para obter mais informações, consulte Estruturas de controle aninhadas.
Sair para e continuar para
A instrução Exit For faz com que a execução saia do For
...Next
loop e transfere o controle para a instrução que segue a Next
instrução.
A Continue For
instrução transfere o controle imediatamente para a próxima iteração do loop. Para obter mais informações, consulte Declaração de continuação.
O exemplo a seguir mostra como usar as Continue For
instruções and 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
Você pode colocar qualquer número de Exit For
instruções em um For Each
loop. Quando usado em loops aninhados For Each
, Exit For
faz com que a execução saia do loop mais interno e transfere o controle para o próximo nível mais alto de aninhamento.
Exit For
é frequentemente usado após uma avaliação de alguma condição, por exemplo, em um If
...Then
...Else
estrutura. Você pode querer usar Exit For
para as seguintes condições:
Continuar a iterar é desnecessário ou impossível. Isso pode ser causado por um valor incorreto ou uma solicitação de rescisão.
Uma exceção é capturada em um
Try
...Catch
...Finally
. Você pode usarExit For
no final doFinally
bloco.Há um loop infinito, que é um loop que pode ser executado um grande ou até infinito número de vezes. Se você detetar tal condição, você pode usar
Exit For
para escapar do loop. Para obter mais informações, consulte Fazer... Instrução Loop.
Iteradores
Você usa um iterador para executar uma iteração personalizada em uma coleção. Um iterador pode ser uma função ou um Get
acessador. Ele usa uma Yield
instrução para retornar cada elemento da coleção, um de cada vez.
Você chama um iterador usando uma For Each...Next
instrução. Cada iteração do For Each
loop chama o iterador. Quando uma Yield
instrução é alcançada no iterador, a expressão na Yield
instrução é retornada e o local atual no código é mantido. A execução é reiniciada a partir desse local na próxima vez que o iterador for chamado.
O exemplo a seguir usa uma função iteradora. A função iterador tem uma Yield
instrução que está dentro de um For... Próximo ciclo. ListEvenNumbers
No método, cada iteração do For Each
corpo da instrução cria uma chamada para a função iterador, que prossegue para a próxima Yield
instrução.
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
Para obter mais informações, consulte Iterators, Yield Statement e Iterator.
Implementação Técnica
Quando um For Each
...Next
executa, o Visual Basic avalia a coleção apenas uma vez, antes do início do loop. Se o bloco de instruções for alterado element
ou group
, essas alterações não afetarão a iteração do loop.
Quando todos os elementos da coleção foram atribuídos sucessivamente ao element
, o For Each
loop para e o controle passa para a instrução após a Next
instrução.
Se Option Infer estiver ativado (sua configuração padrão), o compilador do Visual Basic poderá inferir o tipo de dados de element
. Se ele estiver desativado e element
não tiver sido declarado fora do loop, você deve declará-lo na For Each
declaração. Para declarar o tipo de dados explicitamente element
, use uma As
cláusula. A menos que o tipo de elemento de dados seja definido fora da For Each
construção ...Next
, seu escopo é o corpo do loop. Observe que você não pode declarar element
fora e dentro do loop.
Opcionalmente, Next
você pode especificar element
na instrução. Isso melhora a legibilidade do seu programa, especialmente se você tiver loops aninhados For Each
. Você deve especificar a mesma variável que aparece na instrução correspondente For Each
.
Você pode querer evitar alterar o valor de dentro de element
um loop. Fazer isso pode tornar mais difícil ler e depurar seu código. Alterar o valor de group
não afeta a coleção ou seus elementos, que foram determinados quando o loop foi inserido pela primeira vez.
Quando você estiver aninhando loops, se uma Next
instrução de um nível de aninhamento externo for encontrada antes Next
do de um nível interno, o compilador sinalizará um erro. No entanto, o compilador pode detetar esse erro de sobreposição somente se você especificar element
em cada Next
instrução.
Se seu código depende de percorrer uma coleção em uma ordem específica, um For Each
loop ...Next
não é a melhor escolha, a menos que você conheça as características do objeto enumerador que a coleção expõe. A ordem de travessia MoveNext não é determinada pelo Visual Basic, mas pelo método do objeto enumerador. Portanto, talvez não seja possível prever qual elemento da coleção é o primeiro a ser retornado no element
, ou qual é o próximo a ser retornado após um determinado elemento. Você pode obter resultados mais confiáveis usando uma estrutura de loop diferente, como For
...Next
ou Do
...Loop
.
O tempo de execução deve ser capaz de converter os elementos em group
element
. A instrução [Option Strict
] controla se as conversões de ampliação e estreitamento são permitidas (Option Strict
está desativado, seu valor padrão) ou se apenas conversões de ampliação são permitidas (Option Strict
está ativado). Para obter mais informações, consulte Estreitando conversões.
O tipo de dados de deve ser um tipo de group
referência que se refere a uma coleção ou uma matriz que é enumerável. Mais comumente, isso significa que group
se refere a um objeto que implementa a System.Collections
IEnumerable interface do namespace ou a IEnumerable<T> interface do System.Collections.Generic
namespace. System.Collections.IEnumerable
Define o GetEnumerator método, que retorna um objeto enumerador para a coleção. O objeto enumerador implementa a System.Collections.IEnumerator
interface do System.Collections
namespace e expõe a Current propriedade e os Reset métodos and MoveNext . Visual Basic usa esses para percorrer a coleção.
Estreitando conversões
Quando Option Strict
é definido como On
, estreitar conversões normalmente causa erros do compilador. Em uma For Each
instrução, no entanto, as conversões dos elementos em group
para element
são avaliadas e executadas em tempo de execução, e os erros do compilador causados pelo estreitamento de conversões são suprimidos.
No exemplo a seguir, a atribuição de m
como o valor inicial para n
não compila quando Option Strict
está ativada porque a conversão de a Long
para an Integer
é uma conversão de estreitamento. For Each
Na instrução, no entanto, nenhum erro do compilador é relatado, mesmo que a atribuição a number
exija a mesma conversão de Long
para Integer
. For Each
Na instrução que contém um número grande, um erro em tempo de execução ocorre quando ToInteger é aplicado ao número grande.
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
Chamadas IEnumerator
Quando a execução de um For Each
loop ...Next
é iniciada, o Visual Basic verifica se group
refere a um objeto de coleção válido. Se não, abre uma exceção. Caso contrário, ele chama o MoveNext método e a Current propriedade do objeto enumerador para retornar o primeiro elemento. Se MoveNext
indica que não há nenhum próximo elemento, ou seja, se a coleção estiver vazia, o loop para e o For Each
controle passa para a instrução após a Next
instrução. Caso contrário, o Visual Basic define element
como o primeiro elemento e executa o bloco de instrução.
Cada vez que o Visual Basic encontra a Next
instrução, ele retorna para a For Each
instrução. Novamente ele chama MoveNext
e Current
para retornar o próximo elemento, e novamente ele executa o bloco ou para o loop dependendo do resultado. Esse processo continua até MoveNext
indicar que não há nenhum próximo elemento ou uma Exit For
instrução é encontrada.
Modificando a coleção. O objeto enumerador retornado por GetEnumerator normalmente não permite que você altere a coleção adicionando, excluindo, substituindo ou reordenando quaisquer elementos. Se você alterar a coleção depois de iniciar um For Each
loop ...Next
, o objeto enumerador se tornará inválido e a próxima tentativa de acessar um elemento causará uma InvalidOperationException exceção.
No entanto, esse bloqueio de modificação não é determinado pelo Visual Basic, mas sim pela implementação da IEnumerable interface. É possível implementar IEnumerable
de uma forma que permita a modificação durante a iteração. Se você está pensando em fazer essa modificação dinâmica, certifique-se de entender as IEnumerable
características da implementação na coleção que está usando.
Modificando elementos de coleção. A Current propriedade do objeto enumerador é ReadOnly e retorna uma cópia local de cada elemento de coleção. Isso significa que você não pode modificar os próprios elementos em um For Each
loop ...Next
Qualquer modificação feita afeta apenas a cópia local e não é refletida Current
de volta na coleção subjacente. No entanto, se um elemento for um tipo de referência, você poderá modificar os membros da instância para a qual ele aponta. O exemplo a seguir modifica o BackColor
membro de cada thisControl
elemento. Não pode, no entanto, modificar-se thisControl
a si próprio.
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
O exemplo anterior pode modificar o BackColor
membro de cada thisControl
elemento, embora não possa modificar thisControl
a si mesmo.
Atravessando matrizes. Como a Array classe implementa a IEnumerable interface, todas as matrizes expõem o GetEnumerator método. Isso significa que você pode iterar através de uma matriz com um For Each
loop ...Next
No entanto, você só pode ler os elementos da matriz. Não é possível alterá-los.
Exemplo 1
O exemplo a seguir lista todas as pastas no diretório C:\ usando a 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
Exemplo 2
O exemplo a seguir ilustra um procedimento para classificar uma coleção. O exemplo classifica instâncias de uma Car
classe que são armazenadas em um List<T>arquivo . A Car
classe implementa a IComparable<T> interface, que requer que o CompareTo método seja implementado.
Cada chamada para o CompareTo método faz uma única comparação que é usada para classificação. O código escrito pelo usuário no CompareTo
método retorna um valor para cada comparação do objeto atual com outro objeto. O valor retornado é menor que zero se o objeto atual for menor que o outro objeto, maior que zero se o objeto atual for maior que o outro objeto e zero se eles forem iguais. Isso permite que você defina no código os critérios para maior que, menor que e igual.
ListCars
No método, a cars.Sort()
instrução classifica a lista. Essa chamada para o Sort método do faz com que o List<T>CompareTo
método seja chamado automaticamente para os Car
objetos no 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