Compartilhar via


Para cada... Instrução Next (Visual Basic)

Repete um grupo de instruções para cada elemento em uma coleção.

Sintaxe

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

Partes

Prazo Definição
element Obrigatório na instrução For Each. Opcional na instrução Next . Variável. Usado para iterar por meio 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 objeto. Refere-se à coleção sobre a qual a statements coleção deve ser repetida.
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 Eachloop ...Next quando quiser repetir um conjunto de instruções para cada elemento de uma coleção ou matriz.

Dica

Um para... A Próxima Instrução 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. Nesse tipo de caso, um For Eachloop ...Next é muitas vezes uma escolha melhor.

No exemplo a seguir, o For Each... Next A instrução itera em 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 loops For Each colocando um loop dentro de 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, confira Estruturas de controle aninhadas.

Exit For e Continue For

A instrução Exit For faz com que a execução saia do For... Next e transfere o controle para a instrução que segue a instrução Next.

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 Continue.

O exemplo a seguir mostra como usar as instruções e Exit For as Continue For instruções.

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 geralmente é usado após uma avaliação de alguma condição, por exemplo, em um If...Then...Else estrutura. Talvez você queira 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 encerramento.

  • Uma exceção é capturada em um Try...Catch...Finally. Você pode usar Exit For no final do Finally bloco.

  • Há um loop sem fim, que é um loop que pode executar um número grande ou até infinito de vezes. Se você detectar tal condição, poderá usar Exit For para escapar do loop. Para obter mais informações, consulte Do...Loop Statement.

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 ponto na próxima vez que o iterador for chamado.

O exemplo a seguir usa uma função de iterador. A função iterador tem uma Yield instrução que está dentro de um For... Próximo loop. ListEvenNumbers No método, cada iteração do corpo da For Each 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 Iteradores, Instrução Yield e Iterator.

Implementação técnica

Quando um For Each... Next a instrução é executada, o Visual Basic avalia a coleção apenas uma vez, antes do início do loop. Se a instrução bloquear alterações element ou group, essas alterações não afetarão a iteração do loop.

Quando todos os elementos da coleção tiverem sido atribuídos elementsucessivamente, 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ê deverá declará-lo na instrução For Each . Para declarar o tipo de dados explicitamente element , use uma As cláusula. A menos que o tipo de dados do elemento seja definido fora do For Eachconstructo ...Next , seu escopo é o corpo do loop. Observe que você não pode declarar element fora e dentro do loop.

Opcionalmente, você pode especificar element na instrução Next . Isso melhora a legibilidade do seu programa, especialmente se você tiver loops aninhados For Each . Você deve especificar a mesma variável que a que aparece na instrução correspondente For Each .

Talvez você queira evitar alterar o valor de dentro de element um loop. Fazer isso pode dificultar a leitura e a depuração do código. Alterar o valor não group afeta a coleção ou seus elementos, que foram determinados quando o loop foi inserido pela primeira vez.

Quando você está aninhando loops, se uma Next instrução de um nível de aninhamento externo for encontrada antes do Next nível interno, o compilador sinalizará um erro. No entanto, o compilador poderá detectar esse erro de sobreposição somente se você especificar element em cada Next instrução.

Se o código depender da passagem de uma coleção em uma determinada ordem, um For Eachloop ...Next não será a melhor opção, a menos que você saiba as características do objeto enumerador que a coleção expõe. A ordem de passagem não é determinada pelo Visual Basic, mas pelo MoveNext método do objeto enumerador. Portanto, talvez você não consiga prever em qual elemento da coleção é o primeiro a ser retornado elementou 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 runtime deve ser capaz de converter os elementos em groupelement. A instrução [Option Strict] controla se as conversões de ampliação e restrição são permitidas (Option Strict está desativada, seu valor padrão) ou se apenas conversões de ampliação são permitidas (Option Strict está ativada). Para obter mais informações, consulte Limitações de conversões.

O tipo de dados deve ser um tipo de group referência que se refere a uma coleção ou uma matriz enumerável. Geralmente, isso significa que group se refere a um objeto que implementa a IEnumerable interface do System.Collections namespace ou da 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 ResetMoveNext métodos. O Visual Basic os usa para percorrer a coleção.

Conversões de redução

Quando Option Strict é definido como On, a restrição de conversões normalmente causa erros do compilador. Em uma For Each instrução, no entanto, as conversões dos elementos para element os quais group são avaliadas e executadas em tempo de execução, e os erros do compilador causados pela restrição de conversões são suprimidos.

No exemplo a seguir, a atribuição de m como o valor n inicial não é compilada quando Option Strict está ativada porque a conversão de um Long em um Integer é uma conversão de restrição. Na instrução For Each , no entanto, nenhum erro do compilador é relatado, mesmo que a atribuição exija number a mesma conversão de Long para Integer. Na instrução For Each que contém um número grande, ocorre um erro em tempo de execução 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 de IEnumerator

Quando a execução de um For Eachloop ...Next é iniciada, o Visual Basic verifica se group se refere a um objeto de coleção válido. Caso contrário, gera 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 indicar que não há nenhum próximo elemento, ou seja, se a coleção estiver vazia, o loop será interrompido e o For Each controle passará 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.

Sempre que o Visual Basic encontrar a Next instrução, ele retornará à instrução For Each . Novamente, ele chama MoveNext e Current retorna o próximo elemento e, novamente, executa o bloco ou interrompe o loop dependendo do resultado. Esse processo continua até MoveNext indicar que não há nenhum próximo elemento ou uma instrução Exit For encontrada.

Modificando a coleção. O objeto enumerador retornado normalmente GetEnumerator 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 Eachloop ...Next , o objeto enumerador se tornará inválido e a próxima tentativa de acessar um elemento causará uma exceção InvalidOperationException .

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 maneira que permita a modificação durante a iteração. Se você estiver considerando fazer essa modificação dinâmica, certifique-se de entender as características da IEnumerable implementação na coleção que você 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 Eachloop ...Next Qualquer modificação feita afeta apenas a cópia Current local e não é refletida novamente 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. Você não pode, no entanto, modificar thisControl a si mesmo.

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 ele 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 por meio de uma matriz com um For Eachloop ...Next . No entanto, você só pode ler os elementos da matriz. Você não pode 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>. A Car classe implementa a IComparable<T> interface, que exige que o CompareTo método seja implementado.

Cada chamada para o CompareTo método faz uma única comparação 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 será 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 for igual. Isso permite que você defina no código os critérios para maior que, menor que e igual.

ListCars No método, a instrução cars.Sort() classifica a lista. Esta chamada ao método Sort do List<T> faz com que o método CompareTo seja chamado automaticamente para os objetos Car 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

Consulte também