C# Precedência

Quanto é 2 + 3 * 4? Se você fizer da esquerda para a direita, dá 20. Se fizer a multiplicação primeiro, dá 14. O C# precisa de uma regra para decidir, e essa regra se chama precedência: a ordem em que os operadores são calculados quando aparecem juntos. Nesta aula você vai ver essa ordem, o que acontece quando dois operadores têm a mesma prioridade, os erros clássicos (a média sem parênteses e o texto que "gruda" nos números) e como os parênteses resolvem tudo.

Você vai aprender
  • O que é precedência e por que 2 + 3 * 4 dá 14.
  • A associatividade: por que 10 - 4 - 3 dá 3 e a = b = 7 funciona.
  • Os erros clássicos: a média sem parênteses e "Total: " + 2 + 3 mostrando Total: 23.
  • Onde o (double), o !, as comparações e o &&/|| entram na fila.
  • A tabela completa dos operadores do C# e a regra de ouro: na dúvida, parênteses.

Todos os programas desta aula foram rodados com o .NET 10 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cs, com dotnet run arquivo.cs.


A ideia: a fila do caixa preferencial

Numa fila de supermercado com atendimento preferencial, quem tem prioridade passa na frente, mesmo tendo chegado depois. Entre duas pessoas com a mesma prioridade, vale a ordem de chegada.

Numa conta, os operadores são as pessoas da fila. A precedência diz quem tem prioridade (a multiplicação passa na frente da soma). A associatividade diz o que fazer quando dois têm a mesma prioridade (quase sempre, quem está mais à esquerda vai primeiro). E os parênteses são o gerente: o que está dentro deles é atendido antes de tudo.


1. Multiplicação antes da soma

O C# segue a mesma ordem da matemática da escola: *, / e % (o resto da divisão) vêm antes de + e -.

Console.WriteLine(2 + 3 * 4);
Console.WriteLine((2 + 3) * 4);
Console.WriteLine(10 - 2 % 3);
Console.WriteLine(-2 * -3);
$ dotnet run conta.cs
14      « 3 * 4 = 12 primeiro; depois 2 + 12
20      « os parênteses mandaram fazer 2 + 3 primeiro
8       « 2 % 3 = 2 primeiro (o resto de 2 dividido por 3); depois 10 - 2
6       « o sinal de menos "grudado" no número vem antes de tudo
2 + 3 * 4
O * tem prioridade maior que o +, então o C# calcula 3 * 4 mesmo ele estando à direita. Pense assim: o C# coloca parênteses invisíveis, 2 + (3 * 4).
(2 + 3) * 4
Os parênteses têm a palavra final: o que está dentro deles é calculado primeiro.
10 - 2 % 3
O % está no mesmo nível do * e do / (aula Operadores Aritméticos).
-2 * -3
Um - na frente de um valor, sem nada à esquerda, é o menos unário ("o oposto de"). Ele, o ! e o (double) ficam no topo da fila: são feitos antes de qualquer conta.

2. Mesma prioridade: da esquerda para a direita

Quando os operadores têm a mesma prioridade, o C# vai da esquerda para a direita. Isso se chama associatividade à esquerda, e muda o resultado da subtração e da divisão:

Console.WriteLine(10 - 4 - 3);
Console.WriteLine(100 / 10 / 2);
Console.WriteLine(10 / 3 * 3);
Console.WriteLine(10 * 3 / 3);
int a;
int b;
a = b = 7;
Console.WriteLine(a + " " + b);
$ dotnet run esquerda.cs
3       « (10 - 4) - 3, e não 10 - (4 - 3) = 9
5       « (100 / 10) / 2, e não 100 / (10 / 2) = 20
9       « (10 / 3) * 3 = 3 * 3: a divisão de inteiros já jogou fora o resto
10      « (10 * 3) / 3 = 30 / 3
7 7     « a = (b = 7): a atribuição vai da direita para a esquerda

As linhas 3 e 4 mostram que, com inteiros, até a ordem de * e / faz diferença: 10 / 3 dá 3 (sem a parte quebrada), e aí não tem volta.

A exceção é a atribuição, que vai da direita para a esquerda: em a = b = 7, primeiro b = 7 (que dá 7) e depois a = 7. Funciona, mas uma atribuição por linha é mais fácil de ler.


3. O erro clássico: a média

A Ana tirou 7 e 8. A média é 7,5. Veja o que acontece sem parênteses:

double nota1 = 7;
double nota2 = 8;
Console.WriteLine(nota1 + nota2 / 2);
Console.WriteLine((nota1 + nota2) / 2);
$ dotnet run media.cs
11      « 7 + (8 / 2) = 7 + 4
7,5     « (7 + 8) / 2 = 15 / 2

O programa compila e roda, sem erro nem aviso, e mostra uma média de 11, maior que as duas notas. Erros de precedência são assim: o compilador não tem como saber o que você queria. Por isso, sempre que uma conta tiver soma e divisão juntas, pergunte-se: "qual parte vem primeiro?" e escreva os parênteses.

Missão: o boletim da Ana mostra a média errada. Ponha os parênteses para a média de 7 e 8 aparecer como Média: 7,5. Depois teste com três notas (lembre de dividir por 3).

Média: 7,5
double nota1 = 7;
double nota2 = 8;
double media = nota1 + nota2 / 2;
Console.WriteLine("Média: " + media);
double nota1 = 7;
double nota2 = 8;
double media = (nota1 + nota2) / 2;
Console.WriteLine("Média: " + media);

4. Quando o + junta textos

O + tem dois trabalhos: somar números e juntar textos (aula Strings). Quando um dos lados é texto, o outro vira texto e os dois são colados. Junte isso com a regra "da esquerda para a direita" e veja:

Console.WriteLine("Total: " + 2 + 3);
Console.WriteLine(2 + 3 + " itens");
Console.WriteLine("Total: " + (2 + 3));
Console.WriteLine("Dobro: " + 2 * 3);
$ dotnet run texto.cs
Total: 23     « ("Total: " + 2) + 3 = "Total: 2" + 3 = "Total: 23"
5 itens       « (2 + 3) + " itens" = 5 + " itens"
Total: 5      « os parênteses fizeram a soma antes
Dobro: 6      « o * vem antes do +, então 2 * 3 foi feito primeiro
  1. Linha 1: o primeiro + encontra um texto ("Total: ") e um número (2). Resultado: o texto "Total: 2". O segundo + encontra outro texto e o 3: cola de novo. Nenhuma soma foi feita.
  2. Linha 2: agora os números vêm primeiro: 2 + 3 são dois números, então é soma (5). Só depois aparece o texto.
  3. Linha 4: o * tem prioridade sobre o +, então 2 * 3 é calculado antes de encontrar o texto. Funciona, mas os parênteses deixam mais claro: "Dobro: " + (2 * 3).

O mesmo vale com as comparações (que ficam abaixo do + na fila): "Pode votar? " + idade >= 16 não compila, como você viu em Operadores de Comparação. A interpolação, $"Total: {2 + 3}", evita esse problema de vez (aula Interpolação).


5. O cast vem antes da divisão

O (double) (aula Conversão de Tipos) está no topo da fila, junto com o menos unário. Ele pega só o valor que vem logo depois dele:

int soma = 15;
Console.WriteLine((double)soma / 2);
Console.WriteLine((double)(soma / 2));
$ dotnet run cast.cs
7,5     « ((double)soma) / 2 = 15,0 / 2: divisão de double
7       « (double)(15 / 2) = (double)7: a divisão de inteiros já tinha jogado fora o ,5

Na primeira linha, o soma vira 15.0 antes da divisão, e a conta é feita com vírgula. Na segunda, os parênteses mandaram dividir primeiro (entre inteiros, 7) e só depois converter: tarde demais.


6. Comparações, && e || na fila

As contas vêm antes das comparações, que vêm antes do &&, que vem antes do ||. Por isso esta linha funciona sem nenhum parêntese:

int idade = 70;
bool estudante = false;
decimal total = 80m;
bool desconto = estudante || idade >= 60 + 5 && total > 50m;
Console.WriteLine(desconto);
Console.WriteLine(!estudante == true);
$ dotnet run tudo.cs
True
True

Na linha 4, o C# lê assim, passo a passo:

  1. 60 + 5 → 65 (conta primeiro).
  2. idade >= 65 → true e total > 50m → true (comparações).
  3. true && true → true (o && antes do ||).
  4. estudante || true → true.

Na linha 6, o ! pega só o estudante (é unário, vem antes de tudo): (!estudante) == true. Funciona, mas ninguém quer fazer esse passo a passo para entender uma linha. Compare com a versão com parênteses: estudante || (idade >= 65 && total > 50m). Os detalhes de && × || estão em Operadores Lógicos.


A tabela completa

Do que é feito primeiro (no topo) para o que é feito por último. Os operadores da mesma linha têm a mesma prioridade. Você não precisa decorar: as linhas destacadas em negrito são as que aparecem todo dia.

NívelOperadoresNomeAssociatividade
1x.y f(x) a[i] x?.y x++ x-- new typeof nameofprimários→
2-x +x !x ++x --x (T)x ~x ^x awaitunários e cast—
3x..yintervalo (Índices e Intervalos)—
4switch withexpressões switch e with—
5* / %multiplicação, divisão, resto→
6+ -soma, subtração, juntar textos→
7<< >> >>>deslocamento de bits→
8< > <= >= is ascomparação e teste de tipo→
9== !=igualdade→
10&E sem curto-circuito / de bits→
11^OU exclusivo→
12|OU sem curto-circuito / de bits→
13&&E→
14||OU→
15??"se for null, use…" (Operadores ??, ?. e ??=)←
16c ? a : bternário (Operador Ternário)←
17= += -= *= /= %= ??= … =>atribuição e lambda←

"→" quer dizer "da esquerda para a direita" (10 - 4 - 3 = (10 - 4) - 3); "←", "da direita para a esquerda" (a = b = 7 = a = (b = 7)). Os operadores dos níveis 3, 4, 7, 10 a 12 e 15 aparecem mais tarde no guia; eles estão aqui para a tabela ficar completa.

Um resumo de bolso

unários (- ! (double)) → contas (* / %, depois + -) → comparações (< >, depois == !=) → lógicos (&&, depois ||) → atribuição (=). Fora isso, parênteses.


Formas diferentes: parênteses que "não precisam"

Sem parêntesesCom parêntesesQual usar
a + b * ca + (b * c)Sem: todo mundo conhece a regra da escola.
"Dobro: " + 2 * 3"Dobro: " + (2 * 3)Com: texto e conta juntos confundem.
x > 0 && y > 0(x > 0) && (y > 0)Sem: as comparações já vêm antes do &&, e o código fica limpo.
a || b && ca || (b && c)Com: pouca gente lembra que && vem antes, e o compilador do C# não avisa.
(double)soma / n((double)soma) / nSem: é a forma que você vai ver em todo lugar.

A regra prática: parênteses que deixam a intenção clara são bem-vindos, mesmo quando não mudam o resultado. Parênteses demais, em volta de cada pedaço, atrapalham a leitura. Quando a expressão ficar enorme, divida em variáveis com bons nomes: bool idoso = idade >= 65;.


Quando dá errado

O resultado está errado e não há erro nem aviso

O que significa: é o sintoma típico de precedência: nota1 + nota2 / 2 no lugar de (nota1 + nota2) / 2, ou "Total: " + 2 + 3 no lugar de "Total: " + (2 + 3).

Como consertar: faça a conta à mão, passo a passo, seguindo a tabela; onde o seu passo a passo for diferente do que você queria, ponha parênteses.

error CS0019: O operador "-" não pode ser aplicado a operandos dos tipos "string" e "int"
int compras = 10;
int devolvidas = 3;
Console.WriteLine("Ficaram: " + compras - devolvidas);
$ dotnet run ep1.cs
/home/ana/cs/ep1.cs(3,19): error CS0019: O operador "-" não pode ser aplicado a operandos dos tipos "string" e "int"

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

O que significa: + e - têm a mesma prioridade e vão da esquerda para a direita. O C# fez "Ficaram: " + compras (o texto "Ficaram: 10") e depois tentou tirar 3 de um texto. Com + no lugar do -, o erro seria pior, porque não haveria erro: apareceria Ficaram: 103.

Como consertar: "Ficaram: " + (compras - devolvidas).

error CS1026: ) esperado
int x = 5;
int y = 3;
Console.WriteLine((x + y) * (x - y);
$ dotnet run ep2.cs
/home/ana/cs/ep2.cs(3,36): error CS1026: ) esperado

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

O que significa: há mais parênteses abrindo do que fechando. Conte: WriteLine(, (x e (x abrem três; y) e y) fecham dois. A coluna 36 é onde o C# esperava o que faltou, logo antes do ;.

Como consertar: feche o que abriu: Console.WriteLine((x + y) * (x - y));. Muitos editores pintam o par de cada parêntese quando o cursor está nele.


Exercícios

1. Faça a conta

Quanto vale 4 + 6 / 2?

Resposta:

2. Da esquerda para a direita

Quanto vale 20 - 5 - 5?

Resposta:

3. Texto e números

O que Console.WriteLine(1 + 1 + "1" + 1); mostra?

Saída:

4. Com int soma = 9;, quanto vale (double)(soma / 2)?

5. Qual é calculado primeiro em a || b && c?

6. Por que "Ficaram: " + 10 - 3 não compila?

Missão final: o total do pedido

Missão: o pedido da lojinha tem 2 cadernos de R$ 12,50 e R$ 5,00 de frete. O programa mostra Total: 25,005, um número sem sentido. Descubra o que o C# fez (siga a tabela!) e ponha os parênteses para aparecer Total: 30,00.

Total: 30,00
decimal preco = 12.50m;
int quantidade = 2;
decimal frete = 5m;
Console.WriteLine("Total: " + preco * quantidade + frete);
decimal preco = 12.50m;
int quantidade = 2;
decimal frete = 5m;
Console.WriteLine("Total: " + (preco * quantidade + frete));

A explicação: o * foi feito primeiro (25,00, com as duas casas do 12.50m), o primeiro + colou esse número no texto ("Total: 25,00") e o segundo + colou o frete (5) no fim. Em Formatar Números você vai aprender a mostrar R$ 30,00 do jeito certo.


Resumo

  • Precedência é a ordem dos operadores: unários e cast → * / % → + - → comparações → == != → && → || → ?: → atribuição.
  • Associatividade: na mesma prioridade, da esquerda para a direita (10 - 4 - 3 = 3). A atribuição vai da direita para a esquerda.
  • A média precisa de parênteses: (nota1 + nota2) / 2.
  • Com texto, o + cola: "Total: " + 2 + 3 dá Total: 23. Use "Total: " + (2 + 3) ou a interpolação.
  • O cast pega só o que vem depois: (double)soma / 2 dá 7,5; (double)(soma / 2) dá 7.
  • Erros de precedência quase nunca dão erro de compilação: o resultado só fica errado. Na dúvida, parênteses.