Igualdade e hashing (valor versus referência)
Entenda a igualdade por referência versus por valor, substitua Equals/GetHashCode corretamente, implemente IEquatable e use comparadores personalizados com conjuntos e dicionários.
Igualdade e hashing (valor versus referência) é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 3 de 3. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 3 aulas no total.
Noções básicas de igualdade
Objetivo: Fazer a igualdade funcionar como esperado.
- Igualdade por referência versus igualdade por valor
- Contrato entre Equals e GetHashCode
- IEquatable<T> para obter mais velocidade
- Comparadores personalizados quando não é possível modificar o tipo
Armadilha da igualdade por referência
As classes usam, por padrão, a igualdade por referência. Dois objetos separados com os mesmos dados não são iguais, a menos que implemente a igualdade por valor.
using System;
using System.Collections.Generic;
public sealed class Point // no overrides
{
public int X;
public int Y;
public Point(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
Point a = new Point(1, 2);
Point b = new Point(1, 2);
Console.WriteLine("a == b ? " + (a == b)); // reference equality: False
Console.WriteLine("a.Equals(b) ? " + a.Equals(b)); // False
HashSet<Point> set = new HashSet<Point>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // False (unexpected)
}
}
Igualdade por valor implementada
Implemente IEquatable<T> e substitua Equals e GetHashCode. O hash deve corresponder à igualdade: objetos iguais → mesmo hash.
using System;
using System.Collections.Generic;
public sealed class ValuePoint : IEquatable<ValuePoint>
{
public int X;
public int Y;
public ValuePoint(int x, int y){ X = x; Y = y; }
public bool Equals(ValuePoint other)
{
if (ReferenceEquals(other, null)) return false;
if (ReferenceEquals(this, other)) return true;
return X == other.X && Y == other.Y;
}
public override bool Equals(object obj)
{
return Equals(obj as ValuePoint);
}
public override int GetHashCode()
{
// Simple, stable combination (avoid randomness)
unchecked
{
int hash = 17;
hash = hash * 31 + X.GetHashCode();
hash = hash * 31 + Y.GetHashCode();
return hash;
}
}
}
public class Program
{
public static void Main(string[] args)
{
ValuePoint a = new ValuePoint(1, 2);
ValuePoint b = new ValuePoint(1, 2);
Console.WriteLine("a.Equals(b)? " + a.Equals(b)); // True
HashSet<ValuePoint> set = new HashSet<ValuePoint>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // True (value semantics)
}
}
Comparador personalizado
Passe um IEqualityComparer<T> personalizado para HashSet/Dictionary quando não puder alterar o próprio tipo.
using System;
using System.Collections.Generic;
public sealed class Person // imagine from a library; cannot edit
{
public string Name;
public int BirthYear;
public Person(string name, int year){ Name = name; BirthYear = year; }
}
public sealed class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person a, Person b)
{
if (ReferenceEquals(a, b)) return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false;
return a.Name == b.Name && a.BirthYear == b.BirthYear;
}
public int GetHashCode(Person p)
{
if (ReferenceEquals(p, null)) return 0;
unchecked
{
int h = 23;
h = h * 31 + (p.Name == null ? 0 : p.Name.GetHashCode());
h = h * 31 + p.BirthYear.GetHashCode();
return h;
}
}
}
public class Program
{
public static void Main(string[] args)
{
Person p1 = new Person("Ada", 1815);
Person p2 = new Person("Ada", 1815);
HashSet<Person> set = new HashSet<Person>(new PersonComparer());
set.Add(p1);
Console.WriteLine("Contains p2? " + set.Contains(p2)); // True via comparer
}
}
Contrato e armadilhas
Regras:
- Se Equals(a,b) for true ⇒ GetHashCode(a) == GetHashCode(b)
- A igualdade deve ser reflexiva, simétrica e transitiva
- Use campos imutáveis para gerar o hash sempre que possível
- Não use valores aleatórios em GetHashCode
Observação sobre estrutura e classe
As estruturas são comparadas por seus campos por padrão (semântica de valor). As classes são comparadas por referência, a menos que implemente a igualdade por valor.
using System;
public struct PointS // struct: value type
{
public int X;
public int Y;
public PointS(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
PointS a = new PointS(1, 2);
PointS b = new PointS(1, 2);
Console.WriteLine("Struct equality: " + a.Equals(b)); // True by default (field-wise)
}
}
Contrato de igualdade para coleções
Recapitulação
Recapitulação: as classes precisam de Equals/GetHashCode (e frequentemente de IEquatable<T>) para ter semântica de valor; use comparadores personalizados quando não for possível editar os tipos.
Perguntas Frequentes
A aula “Igualdade e hashing (valor versus referência)” é grátis?
Sim — o texto completo de “Igualdade e hashing (valor versus referência)” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 3 aulas no total.
O que vou aprender em “Igualdade e hashing (valor versus referência)”?
Entenda a igualdade por referência versus por valor, substitua Equals/GetHashCode corretamente, implemente IEquatable e use comparadores personalizados com conjuntos e dicionários. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 3.
Quanto tempo leva a aula “Igualdade e hashing (valor versus referência)”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- HashSet , SortedSet , Queue , Stack
- ConcurrentDictionary , coleções imutáveis
- Igualdade e hashing (valor versus referência)