Partilhar via


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 Eachloop ...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 Eachloop ...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 usar Exit For no final do Finally 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 Eachconstruçã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 Eachloop ...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 groupelement. 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.CollectionsIEnumerable 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 Eachloop ...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 Eachloop ...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 Eachloop ...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 Eachloop ...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

Consulte também