C# if e else
Até agora, todos os seus programas faziam sempre a mesma coisa, linha por linha, de cima para baixo. Um programa de verdade precisa decidir: se a senha está certa, entra; senão, mostra um erro. Se o estoque está baixo, avisa. Nesta aula você vai aprender o if ("se") e o else ("senão"), as ferramentas de decisão mais usadas do C#, e as armadilhas que pegam todo iniciante: as chaves esquecidas, o = no lugar do == e o ; depois do if.
- Como rodar um bloco de código só quando uma condição é verdadeira, com
if. - Como escolher entre dois caminhos com
if…else. - Por que, em C#, a condição tem de ser um
bool(e o erroCS0029quando não é). - Por que usar chaves sempre, e onde colocá-las.
- As armadilhas
if (x = 0)eif (x > 0);(avisoCS0642). - O que acontece com variáveis criadas dentro do bloco (
CS0103) e com variáveis que só ganham valor num dos caminhos (CS0165).
Todos os programas desta aula rodaram com o .NET 10 (C# 14) na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cs, com o comando da aula Rodar com dotnet run: dotnet run arquivo.cs.
A ideia: a bifurcação na estrada
Você está dirigindo e chega numa bifurcação. Uma placa diz: "Se for para a praia, vá pela esquerda; senão, siga pela direita". Você lê a placa, responde à pergunta e segue um dos caminhos, nunca os dois. Logo depois, as duas estradas se juntam de novo e a viagem continua.
Um if é essa placa. Ele faz uma pergunta (a condição), e a resposta, true (sim) ou false (não), decide qual trecho de código roda. As perguntas você já sabe fazer: são as comparações (Operadores de Comparação) e as combinações com &&, || e ! (Operadores Lógicos).
1. O if sozinho
int estoque = 2;
Console.WriteLine($"Estoque: {estoque}");
if (estoque < 5)
{
Console.WriteLine("Atenção: estoque baixo!");
Console.WriteLine("Peça mais ao fornecedor.");
}
Console.WriteLine("Fim do relatório.");
$ dotnet run estoque.cs Estoque: 2 Atenção: estoque baixo! « 2 < 5 é true: o bloco rodou Peça mais ao fornecedor. Fim do relatório. « esta linha está fora do if: roda sempre
- if
- Palavra reservada do C#: "se". Sempre em minúsculas (
IfouIFnão funcionam). - (estoque < 5)
- A condição, obrigatoriamente entre parênteses. Ela tem de dar um
bool: se dertrue, o bloco roda; se derfalse, o bloco é pulado. - { … }
- O bloco: tudo o que está entre as chaves depende do
if. Aqui são doisConsole.WriteLine, e os dois rodam ou nenhum roda. - sem ; depois do )
- A linha do
ifnão termina com ponto e vírgula. Oifsó termina no fim do bloco. (A seção 5 mostra o que acontece se você puser.) - o recuo
- As linhas de dentro ficam 4 espaços mais para a direita. O compilador ignora isso; é para você enxergar o que está dentro do bloco.
Mude o estoque para 10 e o programa mostra só Estoque: 10 e Fim do relatório.: o bloco inteiro é pulado.
Experimente: mude temperatura para valores acima e abaixo de 30 e veja quando o aviso aparece. Depois acrescente um segundo if, que mostra "Leve um casaco." quando a temperatura for menor que 15.
int temperatura = 33;
Console.WriteLine($"Hoje: {temperatura} graus");
if (temperatura > 30)
{
Console.WriteLine("Beba bastante água!");
}
2. O caminho alternativo: else
Com o else ("senão"), você diz o que fazer quando a condição dá false. Exatamente um dos dois blocos roda, nunca os dois e nunca nenhum.
int idade = 17;
if (idade >= 18)
{
Console.WriteLine("Pode tirar a carteira de motorista.");
}
else
{
Console.WriteLine($"Faltam {18 - idade} anos para a carteira.");
}
Console.WriteLine("Fim do programa.");
$ dotnet run idade.cs Faltam 1 anos para a carteira. « 17 >= 18 é false: rodou o else Fim do programa.
Troque o 17 por 30, salve e rode de novo:
$ dotnet run idade.cs Pode tirar a carteira de motorista. « 30 >= 18 é true: rodou o if Fim do programa.
- else
- Vem logo depois da chave que fecha o bloco do
if. Ele não tem condição própria: é "todo o resto". - {18 - idade}
- Dentro do bloco você pode fazer contas e usar as variáveis normalmente. Aqui a conta vai direto na interpolação.
- Fim do programa.
- Depois do
if/else, os dois caminhos se juntam e o programa continua normalmente.
"Faltam 1 anos" ficou feio. Para escolher entre "ano" e "anos" numa linha só, existe o operador ternário. Nesta aula a idade está escrita no código; ler do teclado é assunto de Console.ReadLine.
Missão: o programa diz se o número é par, mas para números ímpares ele não mostra nada. Acrescente um else que mostre que o número é ímpar:
7 é ímpar
int n = 7;
if (n % 2 == 0)
{
Console.WriteLine($"{n} é par");
}
int n = 7;
if (n % 2 == 0)
{
Console.WriteLine($"{n} é par");
}
else
{
Console.WriteLine($"{n} é ímpar");
}
O n % 2 é o resto da divisão por 2 (aula Operadores Aritméticos): 0 para pares, 1 para ímpares positivos. Troque o 7 por 10 e por −3 e rode de novo. Com −3, o resto é −1, que também não é 0: cai no else, certinho.
3. A condição tem de ser bool
Em C#, o que vai entre os parênteses do if tem de ser verdadeiro ou falso: uma comparação, uma variável bool (aula char e bool) ou uma combinação delas.
int mensagens = 3;
bool chovendo = false;
if (mensagens > 0)
{
Console.WriteLine($"Você tem {mensagens} mensagens novas.");
}
if (!chovendo)
{
Console.WriteLine("Pode deixar o guarda-chuva em casa.");
}
$ dotnet run condicao.cs Você tem 3 mensagens novas. « 3 > 0 é true Pode deixar o guarda-chuva em casa. « !false é true
Com uma variável bool, escreva if (chovendo) e if (!chovendo), e não if (chovendo == true): ela já é verdadeira ou falsa.
Quem já viu C, JavaScript ou Python pode tentar usar um número direto como condição. Em C#, não dá:
int mensagens = 3;
if (mensagens)
{
Console.WriteLine("Você tem mensagens.");
}
$ dotnet run numcond.cs /home/ana/cs/numcond.cs(2,5): error CS0029: Não é possível converter implicitamente tipo "int" em "bool" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
"Não é possível converter int em bool" (em inglês, Cannot implicitly convert type 'int' to 'bool'). O (2,5) aponta a linha 2, coluna 5: a variável mensagens dentro do if. O C# não adivinha o que você quis perguntar ("é diferente de zero?", "é maior que zero?"); você tem de escrever a pergunta: if (mensagens > 0). Essa regra parece chata, mas é ela que salva você da armadilha da seção 5.
4. Chaves: use sempre
O C# permite tirar as chaves quando o bloco tem uma instrução só: if (x < 0) x = 0;. Parece prático, mas é a origem de um erro traiçoeiro. A Ana quis zerar o saldo quando a compra fosse maior que ele:
decimal saldo = 100m;
decimal compra = 30m;
if (compra > saldo)
Console.WriteLine("Saldo insuficiente.");
saldo = 0m;
Console.WriteLine($"Saldo: {saldo}");
$ dotnet run semchaves.cs Saldo: 0 « a compra cabia no saldo, mas o saldo foi zerado!
Sem chaves, o if controla só a primeira instrução depois dele (o Console.WriteLine). A linha saldo = 0m; está fora do if e roda sempre. O recuo engana os olhos, mas o compilador não olha recuo. E repare: o dotnet compilou sem nenhum aviso. O compilador do C# não reclama do recuo enganoso; quem salva você aqui é o hábito.
Use { } em todo if e todo else, mesmo com uma linha só. Quando você (ou outra pessoa) acrescentar uma segunda linha depois, ela já vai cair dentro do bloco. Muitas equipes adotam essa regra, e os analisadores do .NET têm até uma sugestão própria para ela, a IDE0011 ("adicionar chaves"). Um erro desse tipo (uma linha duplicada fora das chaves, o famoso goto fail) deixou uma falha de segurança nos aparelhos da Apple em 2014.
Missão: conserte o programa da Ana com chaves, para o saldo só ser zerado quando a compra for maior que ele. Depois troque a compra para 150m e confira que aí, sim, o saldo zera.
Saldo: 100
decimal saldo = 100m;
decimal compra = 30m;
if (compra > saldo)
Console.WriteLine("Saldo insuficiente.");
saldo = 0m;
Console.WriteLine($"Saldo: {saldo}");
decimal saldo = 100m;
decimal compra = 30m;
if (compra > saldo)
{
Console.WriteLine("Saldo insuficiente.");
saldo = 0m;
}
Console.WriteLine($"Saldo: {saldo}");
Onde pôr as chaves
O compilador aceita a chave de abertura na linha de baixo ou na mesma linha:
if (nota >= 6) // estilo do C#: chave na linha de baixo
{
Console.WriteLine("Aprovada");
}
else
{
Console.WriteLine("Reprovada");
}
if (nota >= 6) { // estilo do C, do Java e do JavaScript: chave na mesma linha
Console.WriteLine("Aprovada");
} else {
Console.WriteLine("Reprovada");
}
O primeiro estilo (chamado Allman) é o padrão do C#: é o que a Microsoft usa na documentação e no código do próprio .NET, e o que o dotnet format e os editores produzem. Este guia usa ele. O segundo funciona igual e aparece em código de quem veio de outras linguagens. O importante é usar sempre o mesmo no projeto.
5. Duas armadilhas: = e ;
if (x = 0): guardar no lugar de comparar
Um = sozinho guarda um valor; dois, ==, comparam (aula Operadores de Comparação). Em C, if (vidas = 0) compila (no máximo com um aviso) e zera as vidas. Em C#, a regra da seção 3 pega o erro: vidas = 0 dá um int, e o if exige bool.
int vidas = 3;
if (vidas = 0)
{
Console.WriteLine("Fim de jogo.");
}
$ dotnet run igual.cs /home/ana/cs/igual.cs(2,5): error CS0029: Não é possível converter implicitamente tipo "int" em "bool" /home/ana/cs/igual.cs(1,5): warning CS0219: A variável "vidas" é atribuída, mas seu valor nunca é usado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O conserto é if (vidas == 0). O aviso CS0219 que veio junto é consequência: como o programa só guarda valores em vidas e nunca lê, o compilador acha a variável inútil. Ele some junto com o erro.
Com uma variável bool o compilador não tem como recusar, porque pronto = true dá mesmo um bool. Então ele avisa:
bool pronto = false;
if (pronto = true)
{
Console.WriteLine("Pronto!");
}
$ dotnet run igualbool.cs /home/ana/cs/igualbool.cs(2,5): warning CS0665: Atribuição em expressão condicional é sempre constante. Deseja usar == em vez de = ? /home/ana/cs/igualbool.cs(1,6): warning CS0219: A variável "pronto" é atribuída, mas seu valor nunca é usado Pronto! « pronto era false, mas o if guardou true e entrou
Um aviso não impede o programa de rodar, e o resultado está errado. O próprio aviso sugere o conserto: "Deseja usar == em vez de =?". Melhor ainda: com bool, escreva só if (pronto).
if (…);: o ponto e vírgula que desliga o if
int temperatura = 25;
if (temperatura > 30);
{
Console.WriteLine("Que calor! Ligue o ventilador.");
}
$ dotnet run pontovirgula.cs /home/ana/cs/pontovirgula.cs(2,22): warning CS0642: Instrução empty possivelmente incorreta Que calor! Ligue o ventilador. « com 25 graus?!
- O
;sozinho é uma instrução vazia: "não faça nada". - Então o
ifficou assim: "se a temperatura passar de 30, não faça nada". - O bloco
{ … }da linha de baixo virou um bloco comum, fora doif, e roda sempre.
O aviso, numa tradução meio torta, diz "instrução vazia possivelmente incorreta" (em inglês, Possible mistaken empty statement). A coluna 22 da linha 2 é justamente o ;. Conserto: apague o ;.
Se houver um else, o mesmo ; vira erro de compilação, porque o else fica sem o if dele:
int nota = 4;
if (nota >= 6);
Console.WriteLine("Aprovada");
else
Console.WriteLine("Reprovada");
$ dotnet run elsesolto.cs
/home/ana/cs/elsesolto.cs(3,35): error CS8641: 'else' não pode iniciar uma instrução.
/home/ana/cs/elsesolto.cs(3,35): error CS1003: Erro de sintaxe, "(" esperado
/home/ana/cs/elsesolto.cs(3,35): error CS1525: Termo de expressão inválido "else"
/home/ana/cs/elsesolto.cs(3,35): error CS1026: ) esperado
/home/ana/cs/elsesolto.cs(3,35): error CS1002: ; esperado
Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Cinco erros para um ; só! Leia sempre o primeiro: "else não pode iniciar uma instrução". O if terminou no ;, o Console.WriteLine("Aprovada"); é uma instrução solta, e o else chegou sem nenhum if logo antes. Os outros quatro erros são o compilador, já confuso, tentando entender o else como outra coisa. Conserte o primeiro (apague o ; da linha 2, e ponha chaves) e todos somem.
Repare que o aviso CS0642, que apontaria direto o culpado, não aparece aqui: quando encontra erros de sintaxe (de escrita), o compilador para antes de procurar avisos. O editor do guia faz igual e mostra os mesmos cinco erros. Depois que você apaga o ;, não sobra erro nem aviso.
6. Variáveis e o bloco
Criada dentro, só existe dentro
Uma variável declarada dentro das chaves só existe ali dentro. Quando o bloco termina, ela some:
int pontos = 120;
if (pontos > 100)
{
int bonus = 10;
pontos = pontos + bonus;
}
Console.WriteLine($"Pontos: {pontos}, bônus: {bonus}");
$ dotnet run escopo.cs /home/ana/cs/escopo.cs(7,47): error CS0103: O nome "bonus" não existe no contexto atual Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Na linha 7, fora das chaves, bonus não existe mais. Já pontos, criada fora do if, existe nos dois lugares, e a mudança feita dentro do bloco continua valendo depois. Se você precisa do valor depois do if, declare a variável antes dele. A aula Escopo explica as regras completas.
Valor em um caminho só: CS0165
O C# confere se toda variável tem valor antes de ser lida. Se ela só recebe valor dentro do if, existe um caminho (condição falsa) em que ela fica vazia, e o compilador recusa:
int nota = 8;
string situacao;
if (nota >= 6)
{
situacao = "Aprovada";
}
Console.WriteLine(situacao);
$ dotnet run naoatribuida.cs /home/ana/cs/naoatribuida.cs(7,19): error CS0165: Uso de variável local não atribuída "situacao" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
Mesmo com a nota 8, o compilador não "roda" o programa para ver: ele olha todos os caminhos possíveis. Há dois consertos: dar um valor no else também (else { situacao = "Reprovada"; }), ou dar um valor inicial na declaração (string situacao = "Reprovada";). Com o else, todos os caminhos dão valor, e o erro some.
Formas diferentes de escrever a mesma decisão
| Forma | Exemplo | Quando usar |
|---|---|---|
if com chaves | if (x < 0) { x = 0; } | Sempre. É o padrão deste guia. |
if sem chaves | if (x < 0) x = 0; | Compila com uma instrução só, mas evite: é a origem do erro da seção 4. |
if + else | if (n % 2 == 0) { … } else { … } | Quando há exatamente dois caminhos. |
Dois if separados | if (n % 2 == 0) { … }if (n % 2 != 0) { … } | Evite para caminhos opostos: repete a pergunta e, se você errar uma das duas, os dois blocos podem rodar (ou nenhum). Use else. |
| Mais de dois caminhos | if … else if … else | Aula else if. |
| Escolher um valor | var maior = a > b ? a : b; | Aula Operador Ternário. |
Quando dá errado
error CS0029: Não é possível converter implicitamente tipo "int" em "bool"
O que significa: a condição do if não é verdadeiro/falso. Ou você pôs um número sozinho (if (mensagens)), ou usou = no lugar de == (if (vidas = 0)).
Como consertar: escreva a pergunta completa: if (mensagens > 0), if (vidas == 0).
warning CS0665: Atribuição em expressão condicional é sempre constante
O que significa: você escreveu if (pronto = true), que guarda true em vez de comparar. O programa roda, mas sempre entra no bloco.
Como consertar: if (pronto) (ou if (pronto == true)).
warning CS0642: Instrução empty possivelmente incorreta
O que significa: há um ; logo depois do ) do if. O if não controla nada, e o bloco de baixo roda sempre.
Como consertar: apague o ;: if (temperatura > 30).
error CS8641: 'else' não pode iniciar uma instrução.
O que significa: o else não está logo depois de um if (ou do bloco dele). Causas: um ; depois do if (…), ou um if sem chaves com duas instruções antes do else. Os erros CS1003, CS1525, CS1026 e CS1002 que vêm na mesma linha são consequência dele.
Como consertar: confira se não há ; depois do ) e use chaves: if (…) { … } else { … }.
error CS0103: O nome "bonus" não existe no contexto atual depois de um if
O que significa: a variável foi criada dentro das chaves do if e você a usou fora.
Como consertar: declare a variável antes do if, já com um valor inicial.
error CS0165: Uso de variável local não atribuída "situacao"
O que significa: a variável só recebe valor em um dos caminhos. No outro, ela seria lida sem valor nenhum.
Como consertar: dê um valor também no else, ou dê um valor inicial na declaração.
error CS1003: Erro de sintaxe, "(" esperado
$ cat semparen.cs
int nota = 8;
if nota >= 6
{
Console.WriteLine("Aprovada");
}
$ dotnet run semparen.cs
/home/ana/cs/semparen.cs(2,4): error CS1003: Erro de sintaxe, "(" esperado
/home/ana/cs/semparen.cs(2,13): error CS1026: ) esperado
Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: faltaram os parênteses da condição. Em C# eles são obrigatórios (em Python e em Go, não). O compilador mostra onde esperava o ( (linha 2, coluna 4) e o ) (coluna 13, no fim da condição).
Como consertar: if (nota >= 6).
Referência rápida
| Estrutura | O que faz |
|---|---|
if (cond) { A } | Roda A só se cond for true. |
if (cond) { A } else { B } | Roda A se cond for true; senão, roda B. Sempre exatamente um dos dois. |
if (ativo) / if (!ativo) | Com uma variável bool: "se ativo" / "se não ativo". |
if (a > 0 && b > 0) | Condição composta (Operadores Lógicos). |
if (n) com int n | Erro CS0029: escreva if (n != 0) ou if (n > 0). |
if (x = 0) | Erro CS0029 (com int) ou aviso CS0665 (com bool). Use ==. |
if (cond); | Errado: o ; encerra o if (aviso CS0642). Tire o ;. |
Exercícios
1. Complete o if
Complete para mostrar a mensagem só quando saldo for negativo:
2. Senão
Complete com a palavra que introduz o caminho alternativo:
3. A condição
Complete a condição para o bloco rodar quando vidas for igual a zero:
4. O que este trecho mostra, com int x = 5;? if (x > 10) Console.Write("A"); Console.Write("B");
5. Com int pontos = 50;, o que acontece com if (pontos) { … }?
6. Por que if (n > 0); { Console.WriteLine("positivo"); } mostra "positivo" até com n = -3?
Missão final: o frete grátis
Missão: a lojinha da Ana dá frete grátis para compras de 100 reais ou mais; abaixo disso, o frete é 15 reais. Complete com if e else: no caminho do frete grátis, mostre Frete grátis!; no outro, mostre Frete: R$ 15,00 e some 15 ao total. Sem avisos. Com a compra de 120,50, a saída deve ser:
Frete grátis! Total: R$ 120,50
decimal compra = 120.50m;
decimal total = compra;
// escreva o if e o else aqui
Console.WriteLine($"Total: R$ {total:N2}");
decimal compra = 120.50m;
decimal total = compra;
if (compra >= 100m)
{
Console.WriteLine("Frete grátis!");
}
else
{
Console.WriteLine("Frete: R$ 15,00");
total = total + 15m;
}
Console.WriteLine($"Total: R$ {total:N2}");
Teste também com 99.90m: a saída deve ser Frete: R$ 15,00 e Total: R$ 114,90. E com 100m: frete grátis, porque o "ou mais" pede >=, não >. No código, o número usa ponto (120.50m); na saída, o N2 segue o costume brasileiro e mostra vírgula (aula Formatar Números).
Resumo
if (condição) { … }roda o bloco só quando a condição étrue. Os parênteses são obrigatórios.else { … }é o caminho alternativo: comif/else, exatamente um dos blocos roda. Depois, o programa continua normalmente.- A condição tem de ser
bool: um número sozinho dáCS0029. Com variávelbool, useif (x)eif (!x). - Chaves sempre, no estilo do C# (chave na linha de baixo). Sem elas, o
ifcontrola só a primeira instrução, e o compilador não avisa. if (x = 0)dáCS0029(ou o avisoCS0665combool).if (…);desliga oif(avisoCS0642) e, comelse, dáCS8641.- Variáveis criadas dentro das chaves só existem ali dentro (
CS0103). Uma variável lida depois doifprecisa de valor em todos os caminhos (CS0165).