Compartilhar via


Instrução For Each...Next (Visual Basic)

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

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

Partes

Termo

Definição

element

Necessário na declaração de For Each . Opcional na declaração de Next . Variável. Usado para percorrer os elementos da coleção.

datatype

Necessário se element não já está declarado. Tipo de dados de element.

group

Obrigatório. Uma variável com um tipo que é um tipo ou objeto de coleção. Refere-se a coleção em que statements deve ser repetido.

statements

Opcional. Uma ou mais instruções entre e For EachNext que executam em cada item em group.

Continue For

Opcional. Transfere controle ao início do loop de For Each .

Exit For

Opcional. Transfere controle fora do loop For Each.

Next

Obrigatório. Termina a definição do loop For Each.

Exemplo simples

Use um loop de For Each…Next quando você desejar repetir um conjunto de instruções para cada elemento de uma coleção ou de uma matriz.

Dica

Instrução For...Next (Visual Basic) funciona bem quando você pode associar cada iteração de um loop através de uma variável de controle e determinar os valores inicial e final dessa variável.No entanto, quando você está tratando uma coleção, o conceito de valores inicial e final não é significativo, e você não sabe quantos elementos necessariamente tem a coleção.Neste tipo dos casos, um loop de For Each…Next geralmente é uma opção melhor.

No exemplo, a instrução de For Each…Next itera através de todos os elementos de uma coleção de lista.

' 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 (C# e Visual Basic) e Matrizes no Visual Basic.

Loops aninhados

Você pode aninhar loop de For Each colocando um loop dentro de outro.

O exemplo a seguir demonstra estruturas aninhadas de For Each…Next .

' 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 loop, cada loop deve ter uma variável exclusivo de element .

Você também pode aninhar diferentes tipos de estruturas de controle dentro da outra. Para obter mais informações, consulte Estruturas de controle aninhadas (Visual Basic).

Para e continue para sair

A execução das causas de instrução de Para sair para sair do… loop de ForNext e o transfere controle à declaração que segue a declaração de Next .

O transfere o controle da declaração de Continue For imediatamente para a próxima iteração do loop. Para obter mais informações, consulte Instrução Continue (Visual Basic).

O exemplo a seguir mostra como usar as declarações de Continue For e de 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

Você pode colocar qualquer número de declarações de Exit For em um loop de For Each . Quando usado dentro de loops For Each aninhados, Exit For faz com que a execução sair do controle interno do loop e da transferências de alto nível de aninhamento.

Exit For geralmente é usado após uma avaliação de alguma condição, por exemplo, em um estrutura de If……ThenElse . Você pode usar Exit For nas seguintes circunstâncias:

  • Continuar iterando é desnecessária ou impossível. Isso pode ser causado por um valor errôneo ou por uma solicitação de finalização.

  • Uma exceção é detectada em Try……CatchFinally. Você pode usar Exit For no final do bloco de Finally .

  • Há um loop interminável, que é um loop que é um grande ou mesmo número infinito de vezes. Se você detectar tal condição, você pode usar Exit For para escapar do loop. Para obter mais informações, consulte Instrução Do...Loop (Visual Basic).

Iteradores

Você usa um iterador para executar uma iteração personalizado em uma coleção. Um iterador pode ser uma função ou um acessador de Get . Usa uma instrução de Yield para retornar um de cada vez a cada elemento da coleção.

Você chama um iterador usando uma instrução de For Each...Next . Cada iteração do loop de For Each chama o iterador. Quando uma declaração de Yield é alcançada no iterador, a expressão na declaração de Yield é retornada, e o local atual no código é mantido. A execução é reiniciada de aquele local na próxima vez que o iterador é chamado.

O exemplo a seguir usa uma função de iterador. A função de iterador tem uma instrução de Yield que está dentro de um loop de For… Next . No método de ListEvenNumbers , cada iteração do corpo de instrução de For Each cria uma chamada para a função de iterador, que continua a próxima instrução de Yield .

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 (C# e Visual Basic), Instrução Yield (Visual Basic), e Iterador (Visual Basic).

Implementação técnica

Quando uma declaração de For Each…Next é executado, o Visual Basic avalia a coleção somente uma vez, antes que inicia o loop. Se seu bloco de declaração altera element ou group, essas alterações não afetam a iteração do loop.

Quando todos os elementos na coleção são atribuídos em sucessão a element, as paradas de loop de For Each e para o controle passa para a declaração que segue a declaração de Next .

Se element não foi declarada fora do loop, você deve declará-lo na declaração de For Each . Você pode declarar o tipo de element explicitamente usando uma instrução de As , ou você pode confiar na inferência de tipos para atribuir o tipo. Em ambos os casos, o escopo de element é o corpo do loop. No entanto, você não pode declarar element fora e dentro do loop.

Você pode opcionalmente especificar element na declaração de Next . Isso melhora a legibilidade do seu programa, especialmente se você tem loops aninhados de For Each . Você deve especificar o mesmo variável aquele que aparece na declaração correspondente de For Each .

Você pode desejar evitar alterar o valor de element dentro de um loop. Isso pode fazê-lo mais difícil de ler e depurar seu código. Altere o valor de group não afeta a coleção ou seus elementos, que eram determinados quando o loop foi inserida primeiro.

Quando você tiver loops aninhados, se uma instrução de Next de um nível de aninhamento externo está localizado antes que Next de um nível interno, o compilador sinalizar um erro. No entanto, o compilador pode detectar este erro sobrepostos somente se você especificar element em cada declaração de Next .

Se seu código depende de atravessar uma coleção em uma ordem específica, um loop de For Each…Next não é a melhor opção, a menos que você saiba que as características do objeto que enumerator expõe a coleção. A ordem de passagem não é determinado pelo Visual Basic, mas pelo método de MoveNext de objeto enumerator. Como consequência, você não poderá prever que elemento da coleção é o primeiro a ser retornado em element, ou qual for 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 tipo de dados de element deve ser tal que o tipo de dados dos elementos de group pode ser convertido.

O tipo de dados de group deve ser um tipo de referência que faz referência a uma coleção ou matriz que é enumeráveis. Mais geralmente isso significa que group se refere a um objeto que implementa a interface de IEnumerable de namespace de System.Collections ou a interface de IEnumerable de namespace de System.Collections.Generic . System.Collections.IEnumerable define o método de GetEnumerator , que retorna um objeto enumerator para a coleção. O objeto enumerator implementa a interface de System.Collections.IEnumerator de namespace de System.Collections e expõe a propriedade de Current e métodos de Reset e de MoveNext . Visual Basic usa esses para atravessar a coleção.

Conversões Redutoras

Quando Option Strict é definido como On, conversões causam normalmente erros de compilador. Em uma instrução de For Each , no entanto, conversões de elementos em group a element são avaliadas e executadas em tempo de execução, e os erros de compilador causados 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á ativado porque a conversão de Long a Integer é uma conversão redutora. Na declaração de For Each , no entanto, nenhum erro do compilador é relatado, mesmo que a atribuição a number requer a mesma conversão de Long a Integer. Na declaração de For Each 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 

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

Chamadas de IEnumerator

Quando a execução de um loop de For Each…Next Visual Basic, verifique se group se refere a um objeto válido de coleção. Caso contrário, ele gera uma exceção. Caso contrário, chama o método de MoveNext e a propriedade de Current de objeto enumerator para retornar o primeiro elemento. Se MoveNext indica que não há nenhum elemento seguir, isto é, se a coleção estiver vazia, paradas de loop de For Each e ao controle passa para a declaração que segue a declaração de Next . Caso contrário, o Visual Basic define element para o primeiro elemento e executa o bloco de declaração.

Cada vez que o Visual Basic localize a declaração de Next , retorna para a declaração de For Each . Novamente MoveNext e chama Current para retornar o próximo elemento, e novamente executa o bloco ou para o loop dependendo do resultado. Esse processo continua até que MoveNext indica que não há nenhum elemento seguir ou uma declaração de Exit For está localizado.

Alterando a coleção. O objeto enumerator retornado por GetEnumerator normalmente não permite que você altere a coleção adicionar, excluir, substituição, ou reorganizando quaisquer elementos. Se você altera a coleção depois de iniciou um loop de For Each…Next , o objeto enumerator se torna inválida, e a seguir tentativa para acessar um elemento causa de uma exceção de InvalidOperationException .

No entanto, esse bloqueio de alteração não é determinado por Visual Basic, mas em vez pela implementação da interface de IEnumerable . É possível implementar IEnumerable de uma maneira que permite a alteração durante a iteração. Se você estiver considerando fazendo tal alteração dinâmico, certifique-se de que você entende as características da implementação de IEnumerable na coleção que você está usando.

Elementos de alteração de coleção. A propriedade de Current de objeto enumerator é ReadOnly (Visual Basic), e retorna uma cópia local de cada elemento da coleção. Isso significa que você não pode modificar os próprios elementos em um loop de For Each…Next . Qualquer alteração você faz a afeta somente a cópia local de Current e não é refletido de novo na coleção subjacente. No entanto, se um elemento é um tipo de referência, você pode alterar os membros da instância para qual ele aponta. O exemplo a seguir altera o membro de BackColor de cada elemento de thisControl . Você não pode, no entanto, alterar thisControl próprio.

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

O exemplo anterior pode alterar o membro de BackColor de cada elemento de thisControl , embora não pode alterar thisControl próprio.

Percorrer matrizes. Porque a classe de Array implementa a interface de IEnumerable , todas as matrizes expõe o método de GetEnumerator . Isso significa que você pode percorrer uma matriz com um loop de For Each…Next . No entanto, você pode ler somente os elementos da matriz. Você não pode alterá-los.

Exemplo

O exemplo a seguir lista todas as pastas no diretório de C:\ usando a classe de DirectoryInfo .

Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
    Debug.WriteLine(dir.Name)
Next

O exemplo a seguir ilustra um procedimento para classificar uma coleção. Instâncias de tipos de exemplo de Car classe que são armazenadas em List. A classe de Car implementa a interface de IComparable , que requer que o método de CompareTo seja implementado.

Cada chamada ao método de CompareTo faça uma única comparação que é usada para ordenação. o código de escrito no método de CompareTo retorna um valor para cada comparação do objeto atual com outro objeto. O valor retornado é menor que zero se o objeto atual é menor que o outro objeto, maior que zero se o objeto atual é maior que o outro objeto, e zero se forem iguais. Isso permite que você defina no código os critérios para maior do que, menor que, e iguais.

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

Referência

Instrução For...Next (Visual Basic)

Instrução While...End While (Visual Basic)

Instrução Do...Loop (Visual Basic)

Conceitos

Estruturas de loop (Visual Basic)

Conversões de Widening e Narrowing (Visual Basic)

Inicializadores de objeto: tipos nomeados e anônimos (Visual Basic)

Inicializadores de coleção (Visual Basic)

Outros recursos

Coleções (C# e Visual Basic)

Matrizes no Visual Basic