Uma instrução if executa um bloco de código só quando uma condição é verdadeira. else if adiciona mais testes, e else pega tudo o que os testes não pegaram.
Saída:
Order 120: shipping 0
Order 75.50: shipping 4.99
Order 20: shipping 9.99
As condições são verificadas de cima para baixo e a primeira verdadeira vence. Um pedido de 120 satisfaz >= 100 e nunca chega ao teste >= 50, e é por isso que a condição mais específica vem primeiro. else if não é uma palavra-chave separada: é um else cujo corpo é outro if, então não existe elseif nem elif em C#.
As condições precisam ser bool
C# nunca trata um número, uma string ou um objeto como verdadeiro ou falso. A expressão entre parênteses precisa ser do tipo bool:
int count = 3;
if (count) // error CS0029: Cannot implicitly convert type 'int' to 'bool'
if (count > 0) // correct
if (name) // error: a string is not a bool either
if (name != null) // correct
Isso elimina uma família inteira de bugs de C e JavaScript, onde 0, "" e null contam como falso sem aviso. O preço é escrever a comparação toda vez, o que também deixa a intenção visível para quem ler depois.
Combinando condições com &&, || e !
&& (e), || (ou) e ! (não) combinam testes booleanos. && e || fazem curto-circuito: o lado direito só executa se o lado esquerdo ainda não tiver decidido a resposta.
Saída:
maya: welcome
invalid or banned account
invalid or banned account
omar: age 9 rejected
invalid or banned account
A chamada com null é segura graças ao curto-circuito: quando username != null é falso, username.Length nunca é avaliado, então não há NullReferenceException. Inverta a ordem para username.Length >= 3 && username != null e a mesma chamada quebra.
&& tem precedência maior que ||, então a || b && c significa a || (b && c). Coloque parênteses sempre que misturar os dois; o compilador não precisa deles, mas quem lê precisa. Os operadores de um caractere & e | também funcionam com bool, mas sempre avaliam os dois lados. Use-os só quando o lado direito tiver um efeito colateral que precisa acontecer.
Chaves e a regra de uma instrução
As chaves são opcionais quando um ramo tem uma única instrução. Sem elas, só a próxima instrução pertence ao if, não importa o que a indentação diga:
Saída:
Reorder email sent
Stock: 12
"Reorder email sent" é impresso mesmo com o estoque normal: o segundo WriteLine está fora do if, apesar da indentação. Uma guarda de uma linha como if (x == null) return; funciona bem sem chaves; qualquer coisa que possa ganhar uma segunda linha deve tê-las.
Um bug parecido é um ponto e vírgula logo depois da condição. if (stock < 5); encerra o if com uma instrução vazia, e o bloco seguinte executa incondicionalmente. O compilador sinaliza isso com o aviso CS0642, Possible mistaken empty statement, que vale a pena tratar como erro.
= versus == em uma condição
= atribui, == compara. Para a maioria dos tipos, escrever = por engano não compila, porque o resultado de uma atribuição é o valor atribuído e um int não é um bool:
int score = 10;
if (score = 100) { } // error CS0029: Cannot implicitly convert type 'int' to 'bool'
Com uma variável bool, a atribuição é ela mesma um bool, então o erro de digitação compila:
Saída:
Access granted
isAdmin is now True
A condição sobrescreveu isAdmin e depois testou o novo valor. O compilador avisa (CS0665, atribuição em uma expressão condicional é sempre constante), mas o build ainda passa. Para bools, dispense a comparação: if (isAdmin) e if (!isAdmin) são mais legíveis e não podem ser digitados errado dessa forma.
if aninhado versus guard clauses
Cada nível de aninhamento é mais uma condição que o leitor precisa guardar na cabeça. Quando cada verificação rejeita uma entrada inválida, retorne cedo em vez de aninhar o caminho feliz dentro de todas elas:
Saída:
ordered 2 x keyboard
error: no product
error: quantity must be positive
error: insufficient balance
A versão aninhada do mesmo método teria três níveis de if, com o trabalho real no bloco mais interno e três ramos else se desenrolando no final. Com guard clauses, cada regra fica ao lado da sua mensagem de erro e a última linha é o caso normal. A mesma ideia funciona dentro de laços com continue.
Declarando variáveis na condição
Uma condição pode declarar uma variável que fica em escopo dentro do if. As duas formas comuns são um out var de um método TryParse e o padrão de tipo is:
Saída:
42: positive number 42
abc: not a number
-7: number -7, not positive
string of length 5
TryParse retorna false em vez de lançar uma exceção com entrada inválida, o que o torna a escolha natural para um if. A página de conversão de tipos cobre os métodos de parsing em detalhe.
Quando usar outra coisa
- Escolher um de dois valores: o operador condicional
condition ? a : bé mais curto que umifque atribui nos dois ramos. - Muitos ramos sobre um valor: uma instrução
switchcompara um valor com casos constantes e é mais fácil de ler que dez linhas deelse if. - Mapear um valor para um resultado: uma consulta em um
Dictionarysubstitui uma cadeia longa quando os ramos só diferem nos dados.
Perguntas frequentes
Como escrever else if em C#?
Escreva else if como duas palavras: if (a) { ... } else if (b) { ... } else { ... }. As condições são testadas de cima para baixo e só o primeiro ramo verdadeiro executa, então coloque o teste mais específico primeiro. Não existe palavra-chave elif nem elseif.
Por que não posso escrever if (count) em C#?
Uma condição em C# precisa ser do tipo bool. Ao contrário de C e JavaScript, um int, uma string ou um objeto nunca é convertido para verdadeiro ou falso, então if (count) falha com CS0029, Cannot implicitly convert type 'int' to 'bool'. Escreva o teste que você quer: if (count > 0) ou if (name != null).
Qual a diferença entre && e & em uma condição if?
&& faz curto-circuito: se o lado esquerdo for falso, o lado direito nunca é avaliado, e é isso que torna s != null && s.Length > 0 seguro. & entre dois bools avalia os dois lados sempre. O mesmo vale para || e |. Use && e || em condições, a não ser que você precise do efeito colateral do lado direito.
As chaves são obrigatórias em um if em C#?
Não. Sem chaves, o if controla exatamente uma instrução. Indentar uma segunda linha não a coloca dentro do ramo, o que é uma fonte clássica de bugs, por isso a maioria dos guias de estilo recomenda chaves em todos os ramos.
Posso escrever um if else em uma linha em C#?
Para escolher um valor, use o operador condicional: string label = score >= 50 ? "pass" : "fail";. Para executar instruções, if (x) DoA(); else DoB(); é válido em uma linha, mas é mais difícil de ler e de estender do que um bloco com chaves.