Instruções de iteração (referência de C#)

As instruções a seguir executam repetidamente uma instrução ou um bloco de instruções:

  • A for instrução: executa seu corpo enquanto uma expressão booliana especificada é avaliada como true .
  • A foreach instrução: enumera os elementos de uma coleção e executa seu corpo para cada elemento da coleção.
  • A do instrução: executa condicionalmente seu corpo uma ou mais vezes.
  • A while instrução: executa condicionalmente seu corpo zero ou mais vezes.

A qualquer momento dentro do corpo de uma instrução de iteração, você pode sair do loop usando a instrução break ou ir para a próxima iteração no loop usando a instrução continue.

A instrução for

A instrução for executa uma instrução ou um bloco de instruções enquanto uma expressão booliana especificada é avaliada como true. O exemplo a seguir mostra for a instrução que executa seu corpo enquanto um contador inteiro é menor que três:

for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

O exemplo anterior mostra os elementos da for instrução :

  • A seção do inicializador executada apenas uma vez, antes de inserir o loop. Normalmente, você declara e inicializa uma variável de loop local nessa seção. A variável declarada não pode ser acessada de fora da for instrução .

    A seção inicializador no exemplo anterior declara e inicializa uma variável de contador de inteiros:

    int i = 0
    
  • A seção de condição que determina se a próxima iteração no loop deve ser executada. Se for avaliada como ou não estiver presente, a próxima true iteração será executada; caso contrário, o loop será fechado. A seção condition deve ser uma expressão booliana.

    A seção condição no exemplo anterior verifica se um valor de contador é menor que três:

    i < 3
    
  • A seção iterador que define o que acontece após cada execução do corpo do loop.

    A seção do iterador no exemplo anterior incrementa o contador:

    i++
    
  • O corpo do loop, que deve ser uma instrução ou um bloco de instruções.

A seção iterador pode conter zero ou mais das seguintes expressões de instrução, separadas por vírgulas:

  • prefixo ou sufixo da expressão incrementar, como ++i ou i++
  • prefixo ou sufixo da expressão decrementar, como --i ou i--
  • Atribuição
  • invocação de um método
  • expressão await
  • criação de um objeto usando o operador new

Se você não declarar uma variável de loop na seção inicializador, poderá usar zero ou mais expressões da lista anterior na seção inicializador também. O exemplo a seguir mostra vários usos menos comuns das seções inicializador e iterador: atribuindo um valor a uma variável externa na seção do inicializador, invocando um método nas seções inicializador e iterador e alterando os valores de duas variáveis na seção iterador:

int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
    //...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1

Todas as seções da for instrução são opcionais. Por exemplo, o código a seguir define o for loop infinito:

for ( ; ; )
{
    //...
}

A instrução foreach

A instrução executa uma instrução ou um bloco de instruções para cada elemento em uma instância do tipo que implementa a interface ou , como mostra o foreach exemplo a System.Collections.IEnumerable System.Collections.Generic.IEnumerable<T> seguir:

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

A foreach instrução não está limitada a esses tipos. Você pode usá-lo com uma instância de qualquer tipo que atenda às seguintes condições:

  • Um tipo tem o método público sem GetEnumerator parâmetros. A partir do C# 9.0, o GetEnumerator método pode ser o método de extensão de um tipo.
  • O tipo de retorno do GetEnumerator método tem a propriedade pública e o método público sem Current MoveNext parâmetros cujo tipo de retorno é bool .

O exemplo a seguir usa foreach a instrução com uma instância System.Span<T> do tipo , que não implementa nenhuma interface:

Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (int number in numbers)
{
    Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6

A partir do C# 7.3, se a propriedade do enumerador retornar um valor de retorno de referência ( em que é o tipo de um elemento de coleção), você poderá declarar uma variável de iteração com o modificador ou , como mostra o exemplo Current ref T a T ref ref readonly seguir:

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

Se a instrução foreach for aplicada a null, uma NullReferenceException será gerada. Se a coleção de origem da instrução estiver vazia, o corpo da foreach foreach instrução não será executado e ignorado.

await foreach

A partir do C# 8.0, você pode usar a instrução para consumir um fluxo assíncrono de dados, ou seja, o tipo de coleção que implementa await foreach a IAsyncEnumerable<T> interface. Cada iteração do loop pode ser suspensa enquanto o próximo elemento é recuperado de forma assíncrona. O exemplo a seguir mostra como usar a await foreach instrução :

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

Você também pode usar a await foreach instrução com uma instância de qualquer tipo que atenda às seguintes condições:

  • Um tipo tem o método público sem GetAsyncEnumerator parâmetros. Esse método pode ser o método de extensão de um tipo.
  • O tipo de retorno do método tem a propriedade pública e o método público sem parâmetros cujo tipo de retorno é , ou qualquer outro tipo a espera cujo método awaiter retorna GetAsyncEnumerator Current um MoveNextAsync Task<bool> ValueTask<bool> GetResult bool valor.

Por padrão, os elementos de fluxo são processados no contexto capturado. Se você quiser desabilitar a captura do contexto, use o método TaskAsyncEnumerableExtensions.ConfigureAwait de extensão. Para obter mais informações sobre contextos de sincronização e capturar o contexto atual, consulte Consumindo o padrão assíncronobaseado em tarefa . Para obter mais informações sobre fluxos assíncronos, consulte a seção Fluxos assíncronos do artigo Novidades no C# 8.0.

Tipo de uma variável de iteração

Você pode usar a var palavra-chave para permitir que o compilador infera o tipo de uma variável de iteração na instrução foreach , como mostra o código a seguir:

foreach (var item in collection) { }

Você também pode especificar explicitamente o tipo de uma variável de iteração, como mostra o código a seguir:

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

Na forma anterior, o tipo de um elemento de coleção deve ser implicitamente ou explicitamente conversível no tipo T V de uma variável de iteração. Se uma conversão explícita de T para falhar em tempo de V executar, a foreach instrução lançará um InvalidCastException . Por exemplo, se for um tipo de classe não lacrado, poderá ser qualquer tipo de interface, mesmo aquele T V que não T implementa. Em tempo de execução, o tipo de um elemento de coleção pode ser aquele que deriva de T e, na verdade, implementa V . Se esse não for o caso, um InvalidCastException será lançado.

A instrução do

A instrução do executa uma instrução ou um bloco de instruções enquanto uma expressão booliana especificada é avaliada como true. Como essa expressão é avaliada após cada execução do loop, um loop do é executado uma ou mais vezes. Isso é diferente de um loop while, que executa zero ou mais vezes.

O exemplo a seguir mostra o uso da do instrução :

int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

A instrução while

A instrução while executa uma instrução ou um bloco de instruções enquanto uma expressão booliana especificada é avaliada como true. Como essa expressão é avaliada antes de cada execução do loop, um loop while é executado zero ou mais vezes. Isso é diferente de um loop do, que é executado uma ou mais vezes.

O exemplo a seguir mostra o uso da while instrução :

int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

Especificação da linguagem C#

Para obter mais informações, confira as seguintes seções da especificação da linguagem C#:

Para obter mais informações sobre os recursos adicionados no C# 8.0 e posterior, confira as seguintes notas sobre a proposta de recurso:

Confira também