Comparando objetos e tipos em C#: == vs Equals()

No C#, ao realizar comparações entre objetos e tipos, é comum se deparar com duas formas de comparação: o operador “==” e o método “Equals()”. Embora ambas as abordagens possam, aparentemente, realizar a mesma tarefa, elas têm comportamentos distintos e é importante entender as diferenças entre elas para evitar erros sutis que podem ser difíceis de identificar. Neste artigo vamos explorar essas diferenças de maneira detalhada, fornecendo explicações claras e exemplos práticos.

O operador ==

O operador “==” em C# é um operador binário que, por padrão, compara dois valores. No entanto, o comportamento desse operador pode variar dependendo do tipo de dado que está sendo comparado.

Para tipos primitivos (como int, double, char, bool), o operador “==” compara os valores diretamente. Ou seja, se duas variáveis contiverem o mesmo valor, a comparação retorna “true”, independentemente de estarem na mesma posição de memória ou não.

				
					int num1 = 5;
double num2 = 5.0;
bool resultado = (num1 == num2);

				
			

Para tipos de referência, como classes, o comportamento do “==” muda. Ele passa a comparar os endereços de memória das instâncias, ou seja, se duas variáveis de tipo referência apontam para o mesmo objeto na memória. Se os endereços de memória forem diferentes, o resultado será “false”, mesmo que os valores internos dos objetos sejam idênticos.

				
					public class Pessoa 
{
    public string Nome { get; set; }
}

Pessoa pessoa1 = new Pessoa { Nome = "Maria" };
Pessoa pessoa2 = new Pessoa { Nome = "Maria" };
bool resultado = (pessoa1 == pessoa2);
				
			
No exemplo acima, mesmo que a propriedade “Nome” dos dois objetos “pessoa1” e “pessoa2” sejam iguais, o operador “==” irá comparar os endereços de memória das duas instâncias e, como são objetos distintos, o resultado será “false”.

Agora se fizermos “pessoa2” receber “pessoa1”, temos algo diferente. Vamos ver um exemplo:

				
					Pessoa pessoa1 = new Pessoa { Nome = "Maria" };
Pessoa pessoa2 = pessoa1;

				
			

Agora “pessoa2” não é um novo objeto com as mesmas propriedades que “pessoa1”. Em vez disso, “pessoa2” faz referência à mesma posição que “pessoa1” na memória.

Se fizermos a comparação:

				
					bool resultado = pessoa1 == pessoa2;
Console.WriteLine(resultado);

				
			

O resultado será “true” porque “pessoa1” e “pessoa2” apontam para o mesmo objeto na memória.

O método Equals()

O método “Equals()” é definido pela classe base “Object” e, como todos os tipos em C# herdam de “Object”, todos os tipos de dados (inclusive tipos primitivos e tipos de referência) possuem uma implementação desse método assim como podemos ver no código abaixo.

				
					int numero = 0;
numero.Equals(0);
	
Venda venda = new Venda();
venda.Equals(null);

				
			

Para tipos primitivos o método “Equals()” se comporta de maneira diferente do operador “==”. Ele vai levar em consideração o tipo da variável. Caso os valores que estejam armazenados nas variáveis seja igual, mas os tipos sejam diferentes, será retornado “false”.

				
					int num1 = 5;
double num2 = 5.0;
bool resultado = num1.Equals(num2);

				
			

No exemplo acima, percebemos que quando ele foi executado utilizando o “==” o resultado foi “true”. Porém, utilizando o “Equals()” o resultado foi “false”.

Já para tipos de referência o método Equals() funciona de forma semelhante ao operador ==, comparando, por padrão, os endereços de memória das instâncias. Isso significa que, se duas variáveis referirem-se ao mesmo objeto na memória, o método retornará true; caso contrário, retornará false. No entanto, o método Equals() pode ser sobrescrito em classes para permitir comparações baseadas nos valores dos atributos, tornando a verificação de igualdade mais personalizada e semântica.

				
					public class Pessoa 
{
    public string Nome { get; set; }

    public override bool Equals(object obj) {
        if (obj is Pessoa other) {
            return this.Nome == other.Nome;
        }
        return false;
    }
}

Pessoa p1 = new Pessoa { Nome = "Maria" };
Pessoa p2 = new Pessoa { Nome = "Maria" };
bool resultado = p1.Equals(p2);

				
			

No exemplo acima, a classe “Pessoa” sobrescreve o método “Equals()” para comparar os valores da propriedade “Nome”, em vez de simplesmente verificar se as variáveis apontam para o mesmo objeto. Com isso, o resultado da comparação será “true”.

Comparação com structs

Os structs em C# são tipos de valor. Isso significa que eles são comparados com base nos valores de seus campos, diferentemente dos tipos de referência, que são comparados pelo endereço de memória. Por padrão, o operador “==” não está definido para structs. Isso ocorre porque o compilador não sabe quais campos deve considerar na comparação.

Já o método “Equals()” está disponível para todos os structs e realiza comparações com base nos valores dos campos do objeto. Ele verifica cada propriedade do struct para determinar se os valores são iguais.

				
					public struct Produto
{
    public string Nome { get; set; }
    public decimal Valor { get; set; }
    public bool Disponivel { get; set; }
}

Produto prod1 = new Produto { Nome = "TV", Valor = 3000, Disponivel = true };
Produto prod2 = new Produto { Nome = "TV", Valor = 3000, Disponivel = true };

bool resultado = prod1.Equals(prod2); 

				
			

Na representação acima, podemos observar que o método “Equals()” ao verificar um struct percorre suas propriedades, comparando se os valores de “Nome”, “Valor” e “Disponivel” são iguais nas duas variáveis.

Acelere a sua carreira conosco!

Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET StartClique aqui
Se é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET ExpertClique aqui

Conclusão

Compreender as diferenças entre “==” e “Equals()” é essencial para evitar comportamentos inesperados em seu código. Essa distinção é fundamental, especialmente ao trabalhar com tipos de referência e tipos de valor no C#. Esperamos que este artigo tenha esclarecido o tema e que ajude você na hora de  implementar comparações em seus projetos.