C# foreach

Na aula do for, para visitar cada letra de um nome, você precisou de um contador, de uma condição com Length e de colchetes com a posição, e um <= no lugar errado derrubava o programa. Na maioria das vezes, você só quer dizer: "para cada item desta lista, faça isto". É exatamente o que o foreach ("para cada") faz, sem contador, sem posição e sem a chance de passar do fim.

Você vai aprender
  • Como escrever foreach (tipo item in coleção) { … }.
  • Como usar o foreach com arrays (listas de valores) e com strings (letra por letra).
  • Como somar e contar com um foreach.
  • O que fazer quando você precisa da posição.
  • Por que a variável do foreach não pode ser alterada (CS1656), e outros erros comuns.

Todos os programas desta aula rodaram com o .NET 10 (C# 14) na máquina fictícia da Ana, na pasta ~/cs, com dotnet run arquivo.cs.


A ideia: a lista de compras

No mercado, a Ana tem uma lista de compras no papel. Ela lê o primeiro item, põe no carrinho; lê o segundo, põe no carrinho; e assim até o fim da lista. Ela não pensa "agora vou ao item número 3"; ela só vai passando item por item. Quando a lista acaba, ela vai para o caixa.

O foreach é isso: "para cada item na lista, faça…". Ele começa no primeiro, para no último, e a cada volta entrega um item para você.


1. Uma lista de valores: o array

Para guardar vários valores numa variável só, o C# tem os arrays (vetores). A aula Arrays mostra tudo sobre eles; para esta aula, basta saber criar um:

string[] compras = ["arroz", "feijão", "café", "leite"];
string[]
"Array de string": uma lista de textos. int[] seria uma lista de inteiros; decimal[], de valores em dinheiro.
[ "arroz", … ]
Os itens, entre colchetes, separados por vírgula. Essa forma (a "expressão de coleção") é do C# 12; em código mais antigo você vai ver { "arroz", … } ou new[] { "arroz", … }, que fazem a mesma coisa.
compras.Length
Quantos itens o array tem (aqui, 4).

2. O primeiro foreach

string[] compras = ["arroz", "feijão", "café", "leite"];
foreach (string item in compras)
{
    Console.WriteLine($"- {item}");
}
Console.WriteLine($"{compras.Length} itens na lista.");
$ dotnet run compras.cs
- arroz
- feijão
- café
- leite
4 itens na lista.
foreach
"Para cada". Escreve-se junto, numa palavra só.
string item
A variável da volta: o tipo de cada item (string, porque o array é string[]) e um nome escolhido por você. A cada volta, ela recebe o próximo item.
in
"Em", "dentro de".
compras
A coleção a percorrer: um array, uma string e, mais adiante, listas (List) e outras coleções.
{ … }
O corpo, que roda uma vez para cada item, na ordem em que eles estão.

Não há contador, nem condição, nem passo: o foreach sabe sozinho onde a lista começa e onde termina. Por isso é impossível dar "uma volta a mais" com ele.

Com var

Como o tipo dos itens já está no array, você pode deixar o compilador descobrir (aula var): foreach (var item in compras). Os dois jeitos são iguais e os dois são muito usados. Escrever o tipo ajuda quem está aprendendo a ver o que vem em cada volta.


3. Somar e contar

Os truques do acumulador valem aqui também. A média das notas da Ana:

double[] notas = [7.5, 9.0, 6.0, 8.5];
double soma = 0;
foreach (var nota in notas)
{
    soma += nota;
}
double media = soma / notas.Length;
Console.WriteLine($"Soma: {soma}, média: {media:N2}");
$ dotnet run media.cs
Soma: 31, média: 7,75

A soma deu 31,0, e o .NET mostra um double sem casas decimais quando elas são zero; com {soma:N1} sairia 31,0. A média usa o Length do array: se a Ana acrescentar uma nota, o programa continua certo, sem mexer em mais nada.

Missão: o carrinho da lojinha tem quatro preços. Complete o corpo do foreach para somar cada preço ao total.

Total: R$ 49,15
decimal[] precos = [12.90m, 8.50m, 23.00m, 4.75m];
decimal total = 0m;
foreach (decimal preco in precos)
{
    // some o preço ao total
}
Console.WriteLine($"Total: R$ {total:N2}");
decimal[] precos = [12.90m, 8.50m, 23.00m, 4.75m];
decimal total = 0m;
foreach (decimal preco in precos)
{
    total += preco;
}
Console.WriteLine($"Total: R$ {total:N2}");

4. foreach numa string

Uma string também é uma coleção: de caracteres (char). Com foreach, você passa por eles um a um, sem índice:

string palavra = "banana";
int quantos = 0;
foreach (char letra in palavra)
{
    Console.Write($"[{letra}]");
    if (letra == 'a')
    {
        quantos++;
    }
}
Console.WriteLine();
Console.WriteLine($"\"{palavra}\" tem {quantos} letras 'a'.");
$ dotnet run letras.cs
[b][a][n][a][n][a]
"banana" tem 3 letras 'a'.

Compare com o programa das vogais da aula do for: lá, cada volta fazia char c = frase[i];. Aqui, o foreach já entrega o char pronto em letra. Repare nas aspas: 'a', com aspas simples, é um char (aula char e bool).


5. E se eu precisar da posição?

O foreach entrega o item, não a posição dele. Quando você precisa dos dois, há duas saídas. A primeira: um contador seu, ao lado do foreach:

string[] fila = ["Ana", "Bruno", "Carla"];
int posicao = 1;
foreach (var nome in fila)
{
    Console.WriteLine($"{posicao}º: {nome}");
    posicao++;
}
$ dotnet run posicao.cs
1º: Ana
2º: Bruno
3º: Carla

A segunda: voltar ao for com índice, que é a escolha certa quando a posição é o centro do problema (comparar um item com o seguinte, pular de 2 em 2, andar de trás para a frente). Mais adiante, na aula LINQ, você vai ver um terceiro jeito, com Index().


6. A variável do foreach é só para ler

A Ana quis deixar a lista em maiúsculas trocando cada item:

string[] compras = ["arroz", "feijão", "café"];
foreach (string item in compras)
{
    item = item.ToUpper();
}
$ dotnet run mudar.cs
/home/ana/cs/mudar.cs(4,5): error CS1656: Não é possível atribuir a "item" porque ele é um "variável de iteração foreach"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

"Não é possível atribuir a item, porque ele é a variável de iteração do foreach" (Cannot assign to 'item' because it is a 'foreach iteration variable'). A variável da volta é uma cópia de leitura do item: mudar ela não mudaria o array, então o C# proíbe para você não achar que mudou. Para alterar os itens, use o for com índice, que escreve direto na posição:

string[] compras = ["arroz", "feijão", "café"];
for (int i = 0; i < compras.Length; i++)
{
    compras[i] = compras[i].ToUpper();
}
Console.WriteLine(string.Join(", ", compras));
$ dotnet run mudar2.cs
ARROZ, FEIJÃO, CAFÉ

O string.Join(", ", compras) junta os itens num texto só, com ", " entre eles (aula Métodos de String).


foreach ou for?

SituaçãoUse
Ler cada item, do primeiro ao último (mostrar, somar, contar, procurar)foreach: mais curto e sem risco de passar do fim
Alterar os itens do arrayfor com índice (compras[i] = …)
Precisa da posição, de outra ordem (de trás para a frente) ou de pular itensfor
Repetir um número de vezes, sem coleção (10 voltas, 12 meses)for

Quando dá errado

error CS1656: Não é possível atribuir a "item" porque ele é um "variável de iteração foreach"

O que significa: você tentou mudar a variável da volta.

Como consertar: para alterar os itens, use for com índice. Se só precisa de um valor calculado, crie outra variável: string maiuscula = item.ToUpper();.

error CS0030: Não é possível converter tipo "string" em "int"
$ cat tipo.cs
string[] compras = ["arroz", "feijão", "café"];
foreach (int item in compras)
{
    Console.WriteLine(item);
}
$ dotnet run tipo.cs
/home/ana/cs/tipo.cs(2,1): error CS0030: Não é possível converter tipo "string" em "int"

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: o tipo da variável da volta não combina com o tipo dos itens. O array é de string, e a volta pediu int.

Como consertar: use o tipo dos itens (string item), ou var item.

error CS0230: Um tipo e um identificador são necessários em uma instrução foreach

O que significa: você escreveu foreach (item in compras), sem o tipo. Em JavaScript e em Python se escreve assim; em C#, a variável da volta é declarada ali, e toda declaração precisa de tipo.

Como consertar: foreach (var item in compras) ou foreach (string item in compras).

error CS1579: A instrução foreach não pode operar em variáveis do tipo 'int'…
$ cat numero.cs
int total = 5;
foreach (var n in total)
{
    Console.WriteLine(n);
}
$ dotnet run numero.cs
/home/ana/cs/numero.cs(2,19): error CS1579: A instrução foreach não pode operar em variáveis do tipo 'int' porque 'int' não contém uma definição da extensão ou instância pública para 'GetEnumerator'

Ocorreu uma falha no build. Corrija os erros de build e execute novamente.

O que significa: o foreach só funciona com coleções: coisas que têm itens para entregar um a um (o tal GetEnumerator, que você vai conhecer em IEnumerable e foreach). Um número sozinho não é uma coleção. (Em Python, for n in range(5) faz isso; em C#, é trabalho para o for.)

Como consertar: para repetir 5 vezes, for (int n = 0; n < 5; n++).

error CS1515: 'in' esperado e error CS1003: Erro de sintaxe, "foreach" esperado

O que significa: o costume de outras linguagens. foreach (var item of compras) (o of do JavaScript) dá CS1515: 'in' esperado e mais três erros de sintaxe na mesma linha (no editor do guia, os mesmos quatro). for (var item in compras) (o for … in do Python e do JavaScript) dá CS1003: Erro de sintaxe, "foreach" esperado: o compilador até adivinha o que você queria.

Como consertar: foreach (var item in compras).


Referência rápida

FormaO que faz
foreach (string item in lista) { … }Roda o corpo uma vez para cada item, em ordem.
foreach (var item in lista)O mesmo, com o tipo descoberto pelo compilador.
foreach (char c in texto)Cada caractere de uma string.
string[] x = ["a", "b"]; C# 12Cria um array (antes: { "a", "b" } ou new[] { "a", "b" }).
x.LengthQuantos itens o array (ou a string) tem.
item = …; dentro do foreachErro CS1656: use for para alterar.

Exercícios

1. Para cada

Complete com a palavra do laço:

(var nome in nomes) { Console.WriteLine(nome); }

2. Em

Complete com a palavra que liga a variável à coleção:

foreach (char c "Ana") { Console.Write(c); }

3. Quantas voltas?

Quantas vezes roda o corpo de foreach (char c in "café") { … }?

Voltas:

4. Por que foreach (var p in precos) { p = p * 2; } não compila?

5. Qual laço é a melhor escolha para mostrar cada nome de um array, do primeiro ao último?

6. O que acontece com foreach (var n in 10) { }?

Missão final: o boletim da turma

Missão: a professora da Ana tem as notas da turma num array. Escreva um foreach que, para cada nota, some a nota em soma e conte em aprovados as notas de 7 para cima. As duas linhas do fim já estão prontas. A saída deve ser:

Aprovados: 3 de 6
Média da turma: 6,8
double[] notas = [7.5, 4.0, 9.0, 6.5, 8.0, 5.5];
int aprovados = 0;
double soma = 0;

// escreva o foreach aqui

Console.WriteLine($"Aprovados: {aprovados} de {notas.Length}");
Console.WriteLine($"Média da turma: {soma / notas.Length:N1}");
double[] notas = [7.5, 4.0, 9.0, 6.5, 8.0, 5.5];
int aprovados = 0;
double soma = 0;

foreach (double nota in notas)
{
    soma += nota;
    if (nota >= 7)
    {
        aprovados++;
    }
}

Console.WriteLine($"Aprovados: {aprovados} de {notas.Length}");
Console.WriteLine($"Média da turma: {soma / notas.Length:N1}");

Acrescente mais uma nota ao array (por exemplo, 10.0) e rode de novo: o foreach e o Length se ajustam sozinhos, e a saída vira Aprovados: 4 de 7.


Resumo

  • foreach (tipo item in coleção) { … } roda o corpo uma vez para cada item, do primeiro ao último. Sem contador, sem condição, sem risco de passar do fim.
  • Funciona com arrays (string[], double[]…), com string (cada char) e com as outras coleções do .NET.
  • O tipo da variável da volta tem de combinar com os itens (CS0030); var resolve. O tipo é obrigatório (CS0230).
  • A variável da volta é só para ler (CS1656). Para alterar itens, ou quando precisar da posição, use for.
  • Só coleções podem ser percorridas (CS1579); para repetir N vezes, use for.