C# Operadores de Comparação

Programas tomam decisões o tempo todo: "a nota é suficiente para passar?", "o estoque acabou?", "a senha está certa?". Cada uma dessas perguntas é uma comparação, e a resposta é sempre sim ou não: true (verdadeiro) ou false (falso). Nesta aula você vai conhecer os seis operadores de comparação do C#, ver o que dá para comparar e o que não dá, e aprender as armadilhas de comparar números com vírgula.

Você vai aprender
  • Os seis operadores: ==, !=, >, <, >= e <=.
  • Que toda comparação produz um bool, que pode ser guardado numa variável, e por que o console mostra True com letra maiúscula.
  • O que dá para comparar: números, char, bool e string (só com == e !=).
  • Por que 0.1 + 0.2 == 0.3 dá False com double e True com decimal.
  • Os erros mais comuns: = no lugar de ==, 0 <= nota <= 10 e o texto grudado na comparação.

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 o comando dotnet run arquivo.cs (aula Rodar com dotnet run).


A ideia: perguntas de sim ou não

Pense numa balança de dois pratos. Você coloca uma coisa de cada lado, e ela só sabe responder uma pergunta: qual lado pesa mais, ou se estão iguais. Ela não diz "quanto" pesa; diz só "sim" ou "não" para a pergunta que você fez.

Os operadores de comparação são essa balança. Você põe um valor de cada lado do operador, e o C# responde true ou false. São os sinais da matemática da escola, escritos com as teclas do teclado:

OperadorPerguntaNa matemáticaExemploResposta
==é igual a?=7 == 7true
!=é diferente de?≠7 != 7false
>é maior que?>7 > 5true
<é menor que?<7 < 5false
>=é maior ou igual a?≥7 >= 7true
<=é menor ou igual a?≤8 <= 7false

Três detalhes de escrita que pegam todo iniciante:

  • Igual é com dois sinais: ==. Um sinal só (=) é a atribuição, "guarde este valor" (aula Operadores de Atribuição).
  • Diferente é !=: o ! quer dizer "não", então != se lê "não igual".
  • Nos operadores de dois símbolos, o = vem sempre por último: >= e <=, nunca => nem =<. E não pode haver espaço no meio: > = é erro.

1. A resposta é um bool

A Ana tem 16 anos. Veja as seis perguntas sobre a idade dela:

int idade = 16;
Console.WriteLine(idade == 16);
Console.WriteLine(idade != 16);
Console.WriteLine(idade > 18);
Console.WriteLine(idade < 18);
Console.WriteLine(idade >= 16);
Console.WriteLine(idade <= 15);
$ dotnet run seis.cs
True       « 16 é igual a 16
False      « 16 não é diferente de 16
False      « 16 não é maior que 18
True       « 16 é menor que 18
True       « 16 é maior ou igual a 16 (é igual, e isso basta)
False      « 16 não é menor ou igual a 15

Cada comparação virou um valor do tipo bool (de boolean, "booleano", em homenagem ao matemático George Boole), o tipo que só tem dois valores (aula char e bool). Repare numa diferença:

  • No código, os valores se escrevem com letra minúscula: true e false.
  • Na tela, o Console.WriteLine mostra True e False, com maiúscula. É só o jeito como o .NET transforma um bool em texto. O valor é o mesmo.

Guardar a resposta numa variável

Como a resposta é um valor, ela pode ser guardada numa variável bool, com um nome que diga o que ela significa:

int idade = 17;
bool podeVotar = idade >= 16;
bool podeDirigir = idade >= 18;
Console.WriteLine("Pode votar? " + podeVotar);
Console.WriteLine("Pode dirigir? " + podeDirigir);
Console.WriteLine("Tem 17? " + (idade == 17));
$ dotnet run bool.cs
Pode votar? True
Pode dirigir? False
Tem 17? True
bool podeVotar = idade >= 16;
Lida da direita para a esquerda: o C# primeiro calcula idade >= 16 (17 é maior ou igual a 16? sim, true) e depois guarda o true em podeVotar. O = (um sinal) guarda; o >= pergunta.
"Pode votar? " + podeVotar
Juntar um texto com um bool com + transforma o bool em texto ("True") e cola os dois (aula Strings).
"Tem 17? " + (idade == 17)
Aqui a comparação está dentro da linha, e os parênteses são obrigatórios. Sem eles, o C# faria o + primeiro e tentaria comparar um texto com um número. Você vai ver esse erro em Quando dá errado.
nomes como podeVotar
Variáveis bool costumam ter nome de pergunta ou de estado: podeVotar, estaAprovado, temEstoque, ehAdmin. Assim, if (podeVotar) se lê quase como português (aula if e else).

Experimente: mude a nota para 6, 10 e 3 e rode de novo. Depois acrescente uma linha que pergunte se a nota é diferente de zero.

int nota = 7;
Console.WriteLine("Nota: " + nota);
Console.WriteLine("Passou (6 ou mais)? " + (nota >= 6));
Console.WriteLine("Tirou 10? " + (nota == 10));
Console.WriteLine("Ficou abaixo de 5? " + (nota < 5));

2. O que dá para comparar

Os operadores funcionam com vários tipos, mas cada tipo tem suas regras:

Console.WriteLine(5 == 5.0);
Console.WriteLine(7 / 2 == 3.5);
Console.WriteLine('a' < 'b');
Console.WriteLine('Z' < 'a');
Console.WriteLine(true == false);
string nome = "Ana";
Console.WriteLine(nome == "Ana");
Console.WriteLine(nome == "ana");
Console.WriteLine(nome != "Bia");
$ dotnet run tipos.cs
True       « int com double: o 5 vira 5.0 antes de comparar
False      « 7 / 2 entre inteiros dá 3, e 3 não é 3.5
True       « 'a' vem antes de 'b'
True       « surpresa: 'Z' (código 90) é menor que 'a' (código 97)
False
True       « mesmo texto
False      « maiúscula e minúscula contam: "Ana" não é "ana"
True
Números entre si
int, long, double e decimal podem ser comparados entre si. Antes de comparar, o C# converte o menor para o maior (o 5 vira 5.0). Cuidado com a divisão de inteiros: 7 / 2 é 3 (aula Operadores Aritméticos).
char
Cada letra tem um número na tabela Unicode, e é esse número que se compara. Todas as maiúsculas (A = 65 … Z = 90) vêm antes de todas as minúsculas (a = 97 … z = 122). Por isso 'Z' < 'a' é true. Para ordem alfabética "de verdade", use string.Compare (aula Strings).
bool
Só com == e !=. Não existe "verdadeiro é maior que falso".
string
Em C#, o == compara o conteúdo dos textos, letra por letra. (Quem vem do Java estranha: lá, == em texto é uma armadilha. Em C#, não.) Maiúsculas e minúsculas fazem diferença. Os operadores <, >, <= e >= não funcionam com string: o compilador recusa.
Tipo== e !=< > <= >=Observação
int, long, decimalsimsimexatos
double, floatsim, mas cuidadosimveja a próxima seção
charsimsimcompara o código Unicode
boolsimnãoerro CS0019
stringsim (compara o conteúdo)nãoerro CS0019; use string.Compare
número com stringnãonãoerro CS0019; converta antes (aula Parse e TryParse)

Missão: no Brasil, pode votar quem tem 16 anos ou mais. O programa diz que alguém de 16 anos não pode. Corrija o operador (não mude a idade) para mostrar Pode votar? True.

Pode votar? True
int idade = 16;
bool podeVotar = idade > 16;
Console.WriteLine("Pode votar? " + podeVotar);
int idade = 16;
bool podeVotar = idade >= 16;
Console.WriteLine("Pode votar? " + podeVotar);

3. Cuidado ao comparar double

O double guarda os números em binário, e muitos números "redondos" para nós, como 0,1, não têm representação exata em binário (aula float, double e decimal). Um errinho minúsculo basta para o == responder false:

double a = 0.1 + 0.2;
Console.WriteLine(a == 0.3);
Console.WriteLine(a);
decimal b = 0.1m + 0.2m;
Console.WriteLine(b == 0.3m);
Console.WriteLine(Math.Abs(a - 0.3) < 0.000001);
$ dotnet run double.cs
False                 « para o double, 0,1 + 0,2 não é exatamente 0,3
0,30000000000000004   « o erro está lá na 17ª casa
True                  « com decimal, a conta é exata
True                  « a diferença é menor que 0,000001: "praticamente igual"

Repare que o console mostra 0,30000000000000004 com vírgula: a máquina da Ana está em português, e o .NET usa a vírgula decimal do Brasil ao mostrar números. No código, o separador é sempre o ponto (0.1).

Três jeitos de lidar com isso:

  • Dinheiro e quantidades exatas: use decimal (o m no fim do número quer dizer money). Com ele, 0.1m + 0.2m == 0.3m é true.
  • Medidas (altura, temperatura, distância): use double e compare com tolerância: Math.Abs(a - b) < 0.000001 pergunta "a distância entre os dois é menor que um milionésimo?". Math.Abs é o valor absoluto, o número sem o sinal (aula Matemática).
  • < e > com double são seguros na maioria dos casos ("a temperatura passou de 38?"). O problema é o == exato.
O caso estranho do NaN

0.0 / 0.0 com double não quebra o programa: dá NaN (Not a Number, "não é um número"). E o NaN não é igual a nada, nem a si mesmo: nada == nada é False. Para perguntar se um valor é NaN, use double.IsNaN(nada), que dá True.


4. = não é ==

É o erro mais famoso da programação: escrever um sinal de igual só, quando a intenção era perguntar. Em C#, na maioria dos casos o compilador salva você:

int x = 5;
if (x = 5)
{
    Console.WriteLine("cinco");
}
$ dotnet run e3.cs
/home/ana/cs/e3.cs(2,5): error CS0029: Não é possível converter implicitamente tipo "int" em "bool"
/home/ana/cs/e3.cs(1,5): warning CS0219: A variável "x" é atribuída, mas seu valor nunca é usado

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

O if (aula if e else) exige uma resposta bool. Mas x = 5 é uma atribuição, e o resultado de uma atribuição é o valor guardado: o int 5. Daí o erro CS0029: "não dá para transformar um int num bool". O conserto é if (x == 5). (Em C e em C++ esse código compila e roda errado. O C# não deixa.)

Com uma variável bool, porém, a atribuição já é um bool, e o compilador só pode avisar:

bool aprovado = false;
if (aprovado = true)
{
    Console.WriteLine("Parabéns!");
}
$ dotnet run e7.cs
/home/ana/cs/e7.cs(2,5): warning CS0665: Atribuição em expressão condicional é sempre constante. Deseja usar == em vez de = ?
/home/ana/cs/e7.cs(1,6): warning CS0219: A variável "aprovado" é atribuída, mas seu valor nunca é usado
Parabéns!     « o aluno reprovado ganhou parabéns!

O programa rodou e deu a resposta errada: aprovado = true guardou true na variável, e o if recebeu esse true. O aviso CS0665 pergunta exatamente: "você queria usar == em vez de =?". Avisos não impedem o programa de rodar, mas quase sempre apontam um erro de verdade: leia todos (aula Avisos do Compilador). Com um bool, nem precisa comparar: escreva só if (aprovado).


Formas diferentes de fazer a mesma pergunta

Esta forma……é igual a estaQual usar
idade >= 18idade > 17Iguais só para inteiros. Use a que tem o número da regra: "maior de idade é 18 ou mais" → >= 18. Com double, 17.5 > 17 é true, e as duas deixam de ser iguais.
a < bb > aA que se lê mais naturalmente: preco < 100 ("o preço é menor que 100") em vez de 100 > preco.
aprovado == trueaprovadoA forma curta. O bool já é a resposta.
aprovado == false!aprovadoOs dois aparecem bastante. O ! ("não") é assunto da próxima aula, Operadores Lógicos.
nome == "Ana"nome.Equals("Ana")==. O Equals com opções (como ignorar maiúsculas) aparece em Strings.

Quando dá errado

error CS0019: O operador ">=" não pode ser aplicado a operandos dos tipos "string" e "int"
int idade = 16;
Console.WriteLine("Pode votar? " + idade >= 16);
$ dotnet run e1.cs
/home/ana/cs/e1.cs(2,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: o + é feito antes do >= (aula Precedência). O C# juntou "Pode votar? " + idade, que deu o texto "Pode votar? 16", e depois tentou perguntar se esse texto é maior ou igual a 16. Texto com número não se compara. Em inglês: Operator '>=' cannot be applied to operands of type 'string' and 'int'.

Como consertar: parênteses em volta da comparação: "Pode votar? " + (idade >= 16).

error CS0019: O operador "<=" não pode ser aplicado a operandos dos tipos "bool" e "int"
int nota = 7;
Console.WriteLine(0 <= nota <= 10);
$ dotnet run e2.cs
/home/ana/cs/e2.cs(2,19): error CS0019: O operador "<=" não pode ser aplicado a operandos dos tipos "bool" e "int"

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

O que significa: na matemática, 0 ≤ nota ≤ 10 é uma frase só. No C#, são duas operações: primeiro 0 <= nota, que dá true; depois true <= 10, e um bool não se compara com um número.

Como consertar: faça as duas perguntas completas e junte com && ("e"): nota >= 0 && nota <= 10. É o assunto da próxima aula, Operadores Lógicos.

error CS0029: Não é possível converter implicitamente tipo "int" em "bool"

O que significa: você escreveu if (x = 5), com um sinal de igual só. Isso é uma atribuição, que dá um int, e o if precisa de um bool.

Como consertar: if (x == 5).

warning CS0665: Atribuição em expressão condicional é sempre constante. Deseja usar == em vez de = ?

O que significa: mesmo erro de cima, mas com uma variável bool: o programa compila, roda e sempre entra no if.

Como consertar: if (aprovado) (ou if (aprovado == true)).

error CS1525: Termo de expressão inválido "<"
int x = 5;
Console.WriteLine(x =< 10);
$ dotnet run e4.cs
/home/ana/cs/e4.cs(2,22): error CS1525: Termo de expressão inválido "<"

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

O que significa: =< não existe. O C# leu um = (atribuição) e depois encontrou um < solto, onde esperava um valor. A coluna 22 aponta o <.

Como consertar: o = vem por último: x <= 10.

error CS0019: O operador "<" não pode ser aplicado a operandos dos tipos "string" e "string"
string a = "Ana";
string b = "Bia";
Console.WriteLine(a < b);
$ dotnet run e5.cs
/home/ana/cs/e5.cs(3,19): error CS0019: O operador "<" não pode ser aplicado a operandos dos tipos "string" e "string"

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

O que significa: textos não têm "maior" e "menor" com < e > no C#.

Como consertar: para saber a ordem alfabética, use string.Compare(a, b), que dá um número negativo quando a vem antes (aula Strings).

error CS0019: O operador "==" não pode ser aplicado a operandos dos tipos "int" e "string" e warning CS1718
int idade = 20;
string texto = "20";
Console.WriteLine(idade == texto);
Console.WriteLine(idade == idade);
$ dotnet run e6.cs
/home/ana/cs/e6.cs(3,19): error CS0019: O operador "==" não pode ser aplicado a operandos dos tipos "int" e "string"
/home/ana/cs/e6.cs(4,19): warning CS1718: Comparação feita com a mesma variável. Você pretendia comparar com outro elemento?

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

O que significa: o número 20 e o texto "20" são coisas diferentes para o C#: um é quantidade, o outro são dois caracteres. A linha 4 compila, mas o aviso CS1718 lembra que comparar uma variável com ela mesma é sempre true: provavelmente você digitou o nome errado.

Como consertar: transforme o texto em número antes (int.Parse(texto), aula Parse e TryParse) e confira os nomes das variáveis.


Referência

OperadorNomea = 7, b = 5Funciona com
a == bigual afalsetodos os tipos (texto compara o conteúdo)
a != bdiferente detruetodos os tipos
a > bmaior quetruenúmeros e char
a < bmenor quefalsenúmeros e char
a >= bmaior ou igual atruenúmeros e char
a <= bmenor ou igual afalsenúmeros e char
Math.Abs(x - y) < 0.000001"quase igual"—double e float
double.IsNaN(x)é NaN?—double e float

O resultado de todos é um bool: true ou false no código, True ou False na tela.


Exercícios

1. Diferente

Complete com o operador "diferente de":

bool mudou = senhaNova senhaAntiga;

2. Aprovação

Aprova quem tira 6 ou mais. Complete:

bool aprovado = nota 6;

3. Os parênteses

O que falta para esta linha compilar? Reescreva a parte depois do +:

Console.WriteLine("Maior de idade? " + );

4. O que Console.WriteLine(10 > 3); mostra?

5. O que Console.WriteLine('Z' < 'a'); mostra?

6. Com string nome = "Ana";, quanto vale nome == "Ana" em C#?

7. Por que 0 <= nota <= 10 não compila?

Missão final: o troco da lojinha

Missão: o caixa da lojinha da Ana soma duas moedas (R$ 0,10 e R$ 0,20) e confere se deu o preço da bala, R$ 0,30. Com double, o programa diz que não deu. Troque os tipos por decimal (lembre do m no fim de cada número) para mostrar Troco certo? True.

Troco certo? True
double pago = 0.1 + 0.2;
double preco = 0.3;
Console.WriteLine("Troco certo? " + (pago == preco));
decimal pago = 0.1m + 0.2m;
decimal preco = 0.3m;
Console.WriteLine("Troco certo? " + (pago == preco));

Depois de cumprir a missão, tente tirar o m do 0.3m e leia o erro do compilador: error CS0664: Literal do tipo double não pode ser convertido implicitamente no tipo "decimal"; use um sufixo "M" para criar um literal desse tipo. Sem o m, 0.3 é um double, e o C# não transforma double em decimal sozinho (aula float, double e decimal).


Resumo

  • Seis operadores: ==, !=, >, <, >=, <=. Igualdade tem dois sinais; nos compostos, o = vem por último.
  • Toda comparação dá um bool, que pode ser guardado: bool aprovado = nota >= 6;. Na tela ele aparece como True ou False.
  • Dentro de um texto com +, ponha a comparação entre parênteses: "Passou? " + (nota >= 6).
  • Números se comparam entre si (5 == 5.0 é true); char compara códigos Unicode; bool só com == e !=.
  • string: == e != comparam o conteúdo; < e > não existem (CS0019).
  • double: == exato é perigoso. Para dinheiro, decimal; para medidas, tolerância com Math.Abs.
  • = no lugar de == dá CS0029 (com números) ou o aviso CS0665 (com bool).
  • "Entre dois valores" são duas comparações: nota >= 0 && nota <= 10.