Instruções de iteração – for
, foreach
, do
e while
As instruções de iteração executam uma instrução ou um bloco de instruções repetidas vezes. A instrução for
executa o bloco correspondente enquanto uma expressão booliana especificada é avaliada como true
. A instrução foreach
enumera os elementos de uma coleção e executa o bloco correspondente para cada elemento dessa coleção. A instrução do
executa condicionalmente o bloco correspondente uma ou mais vezes. A instrução while
executa condicionalmente o bloco correspondente zero ou mais vezes.
A qualquer momento dentro do corpo da instrução de iteração, interrompa o loop usando a instrução break
. Você pode passar 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 seguinte exemplo mostra a instrução for
que executa o corpo dela 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 instrução for
:
A seção inicializador é executada apenas uma vez, antes de entrar no loop. Normalmente, você declara e inicializa a variável local do loop nessa seção. A variável declarada não pode ser acessada de fora da instrução
for
.A seção inicializador do exemplo anterior declara e inicializa a variável do contador inteiro:
int i = 0
A seção condição determina se a próxima iteração do loop deve ser executada. Se ela for avaliada como
true
, ou se não estiver presente, a próxima iteração será executada; caso contrário, o loop será encerrado. A seção condição deve corresponder a uma expressão booliana.A seção condição do exemplo anterior verifica se o valor do contador é menor que três:
i < 3
A seção iterador define o que acontece após cada execução do corpo do loop.
A seção iterador do exemplo anterior incrementa o contador:
i++
O corpo do loop deve corresponder a uma instrução ou a 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
oui++
- prefixo ou sufixo da expressão decrementar, como
--i
oui--
- atribuição
- invocação de um método
- Expressão
await
- criação de um objeto usando o operador
new
Se não declarar uma variável de loop na seção inicializador, você poderá usar zero ou mais das expressões da lista anterior na seção inicializador também. O seguinte exemplo 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 instrução for
são opcionais. Por exemplo, o seguinte código define um loop for
infinito:
for ( ; ; )
{
//...
}
A instrução foreach
A instrução foreach
executa uma instrução ou um bloco de instruções para cada elemento em uma instância do tipo que implementa a interface System.Collections.IEnumerable ou System.Collections.Generic.IEnumerable<T>, como mostra o seguinte exemplo:
List<int> fibNumbers = new() { 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 instrução foreach
não se limita a esses tipos. Você pode usá-la com uma instância de qualquer tipo que satisfaça as seguintes condições:
- Um tipo tem o método público sem parâmetros
GetEnumerator
. O métodoGetEnumerator
pode ser o método de extensão de um tipo. - O tipo de retorno do método
GetEnumerator
tem a propriedade públicaCurrent
e o método público sem parâmetrosMoveNext
, cujo tipo de retorno ébool
.
O seguinte exemplo usa a instrução foreach
com uma instância do tipo System.Span<T>, que não implementa nenhuma interface:
Span<int> numbers = [3, 14, 15, 92, 6];
foreach (int number in numbers)
{
Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6
Se a propriedade Current
do enumerador retornar um valor de retorno de referência (ref T
em que T
é o tipo de elemento de uma coleção), você poderá declarar uma variável de iteração com o modificador ref
ou ref readonly
, como mostra o seguinte exemplo:
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 coleção de origem da instrução foreach
estiver vazia, o corpo da instrução foreach
não será executado e será ignorado. Se a instrução foreach
for aplicada a null
, uma NullReferenceException será gerada.
await foreach
Você pode usar a instrução await foreach
para consumir um fluxo assíncrono de dados, ou seja, o tipo de coleção que implementa a interface IAsyncEnumerable<T>. Cada iteração do loop pode ser suspensa enquanto o próximo elemento é recuperado de maneira assíncrona. O seguinte exemplo mostra como usar a instrução await foreach
:
await foreach (var item in GenerateSequenceAsync())
{
Console.WriteLine(item);
}
Você também pode usar a instrução await foreach
com uma instância de qualquer tipo que atenda às seguintes condições:
- Um tipo tem o método público sem parâmetros
GetAsyncEnumerator
. Esse método pode ser o método de extensão de um tipo. - O tipo de retorno do método
GetAsyncEnumerator
tem a propriedade públicaCurrent
e o método público sem parâmetrosMoveNextAsync
, cujo tipo de retorno éTask<bool>
,ValueTask<bool>
ou qualquer outro tipo aguardável cujo métodoGetResult
do awaiter retorna um valorbool
.
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 de extensão TaskAsyncEnumerableExtensions.ConfigureAwait. Para obter mais informações sobre contextos de sincronização e capturar o contexto atual, confira Como consumir o padrão assíncrono baseado em tarefa. Para obter mais informações sobre fluxos assíncronos, confira o Tutorial sobre fluxos assíncronos.
Tipo de variável de iteração
Você pode usar a palavra-chave var
para permitir que o compilador infira o tipo da variável de iteração na instrução foreach
, como mostra o seguinte código:
foreach (var item in collection) { }
Observação
O tipo de var
pode ser inferido pelo compilador como um tipo de referência anulável, dependendo de se o contexto com reconhecimento anulável está habilitado e se o tipo de uma expressão de inicialização é um tipo de referência.
Para obter mais informações, consulte Variáveis locais de tipo implícito.
Você também pode especificar explicitamente o tipo da variável de iteração, como mostra o seguinte código:
IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }
No formulário anterior, o tipo T
de elemento da coleção deve ser implicitamente ou explicitamente conversível para o tipo V
da variável de iteração. Se a conversão explícita de T
para V
falhar em tempo de execução, a instrução foreach
vai gerar o erro InvalidCastException. Por exemplo, se T
for um tipo de classe não selado, V
pode ser de qualquer tipo de interface, mesmo aquele que T
não implementa. Em tempo de execução, o tipo de elemento da coleção pode ser aquele que deriva de T
e, na prática, implementa V
. Se esse não for o caso, o erro InvalidCastException é gerado.
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. Esse loop do
é diferente do loop while
, que é executado zero ou mais vezes.
O seguinte exemplo mostra o uso da instrução do
:
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. Esse loop while
é diferente do loop do
, que é executado uma ou mais vezes.
O seguinte exemplo mostra o uso da instrução while
:
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 esses recursos, confira as seguintes notas sobre a proposta de recurso: