Skip to content

Latest commit

 

History

History
104 lines (77 loc) · 6 KB

README.md

File metadata and controls

104 lines (77 loc) · 6 KB

Comparação de Objetos em C#

Enquanto a comparação de valores de variáveis primitivas como inteiros ou strings e value types como bytes e chars pode ser fácil, a comparação de dois objetos em uma linguagem cmo C# é difícil. Para entender a razão disso você precisa entender primeiro o que são objetos. Leia a seção "O que são objetos". Se isso não for segredo para você pule para a seção "Comparação de Objetos".

O que são objetos?

Quando você cria uma variável "a" do tipo int, double, byte, char no C# você está reservando um espaço de memória, dando o nome para ele e armazenando o valor ali. A variável contém o próprio valor. Se você cria uma nova variável "b" e atribui o valor de a, nesse momento você copiou o valor e as duas são iguais. Se você mudar o valor de "a" os dois valores passarão a ser diferentes.

int a = 2; //a armazena 2, é o próprio valor
int b = a; //copio o valor de a em b
bool antes =  (a == b); //verdadeiro
a = 3; //mudo  o valor de a
bool depois =  (a == b); //falso

Com isso provamos que "a" e "b" não são a mesma "variável", não estão no mesmo lugar na memória.

Mas com objetos (reference types) a coisa é diferente.

Considere que você tem uma classe Usuario feita da seguinte maneira:

    public class UsuarioClasse
    {
        public int Id { get; set; }
        public string Nome { get; set; }
        public DateTime DataNascimento { get; set; }
    }

E você cria UM objeto assim:

E você cria dois objetos idênticos em suas propriedades:

    UsuarioClasse uc1 = new UsuarioClasse { Id = 1, Nome = "João", DataNascimento = DateTime.Today };
    UsuarioClasse uc2 = uc1;

Esses objetos são iguais? Se você chamar uc1 == uc2 ou uc1.Equals(uc2) ambos vão ser verdadeiros

    Console.WriteLine($"Os itens são iguais com == ? {uc1 == uc2}");
    Console.WriteLine($"Os itens são iguais com .Equals ? {uc1.Equals(uc2)}");

Mas se você mudar uma propriedade de uc1, por exemplo uc1.Nome = "Jose", ainda assim os dois objetos serão iguais. E se verificar o valor de uc2.Nome verá que o nome "mudou sozinho".

    uc1.Nome = "Jose";
    Console.WriteLine(uc2.Nome); //saiu "José", mas não era "João" ?
    Console.WriteLine($"Os itens são iguais com == ? {uc1 == uc2}"); //verdadeiro
    Console.WriteLine($"Os itens são iguais com .Equals ? {uc1.Equals(uc2)}"); //verdadeiro    

Como você percebeu, diferentemente dos nossos inteiros "a" e "b", as variáveis "uc1" e "uc2" são o MESMO objeto e não podem ser modificadas separadamente. Isso acontece porque um objeto é uma instância de uma classe na memória, e as variáveis "uc1" e "uc2" são referências que apontam para esse objeto. Ou seja, "uc1" e "uc2" são PONTEIROS e como elas apontam para o mesmo objeto, no mesmo lugar, você não tem dois objetos, você na verdade tem um único objeto com duas variáveis apontando pra ele.

E se você criar dois objetos idênticos em suas propriedades, mas com instâncias diferentes?

    UsuarioClasse uc1 = new UsuarioClasse { Id = 1, Nome = "João", DataNascimento = DateTime.Today };
    UsuarioClasse uc2 = new UsuarioClasse { Id = 1, Nome = "João", DataNascimento = DateTime.Today };

A pergunta é: será que esses objetos são iguais? Como podemos compará-los?

    Console.WriteLine($"Os itens são iguais com == ? {uc1 == uc2}"); //falso
    Console.WriteLine($"Os itens são iguais com .Equals ? {uc1.Equals(uc2)}"); //falso

O método Equals vai retornar true se e somente se dois objetos são exatamente a mesma instância.

Como vimos, a comparação desses dois objetos sempre vai ser falsa, apesar dos valores das propriedades serem iguais. Esses dois objetos são diferentes porque você de fato tem duas instâncias diferentes na memória.

O .Net Framework vem com algumas soluções padrões para comparação de alguns objetos e estruturas. Você pode criar uma struct, record ou record struct, nesses tipos de dados a comparação com == funciona. Lembrando que record é um reference type também, é um tipo especial de classe, enquanto structs e record structs são tipos estruturados (value types) semelhantes ao struct de C/C++ ou ao record do Pascal/Delphi.

Existe também a possibilidade de fazer o override do .Equals e do operador ==, ou de implementar a interface IEquatable.

E por último, quando você precisa comparar as propriedades de objetos de tipos diferentes e ainda ignorar algumas propriedades (como Ids, que geralmente são gerados automaticamente pelo banco de dados), você pode criar alguma estratégia de Shallow Compare ou comparação rasa.

Guia deste repositório

Fontes