Implementando IEquatable
Forneça igualdade com segurança de tipos usando Equals.
Implementando IEquatable é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 1 de 4. 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 4 aulas no total.
Por que IEquatable<T>?
IEquatable<T> fornece um método Equals(T other) fortemente tipado. Ele evita o encaixotamento para tipos de valor e conversões de tipo para tipos de referência, tornando a igualdade mais rápida e clara.
Implementando a interface
Implemente IEquatable<T> e forneça Equals(T other). Você também deve substituir o object.Equals herdado e GetHashCode para manter todos os caminhos consistentes.
using System;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Point(1, 2).Equals(new Point(1, 2)));
}
}Evitando o encaixotamento de estruturas
O método não genérico object.Equals(object) encaixota um argumento de estrutura. O método tipado Equals(Point other) de IEquatable<T> recebe a estrutura diretamente, portanto nenhuma alocação ocorre.
using System;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y; // no boxing
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
Point a = new Point(3, 4);
Point b = new Point(3, 4);
Console.WriteLine(a.Equals(b)); // calls the typed overload
}
}As coleções usam IEquatable<T>
List<T>.Contains, Dictionary e HashSet dão preferência a IEquatable<T>.Equals quando ele está disponível. Implementá-lo torna essas operações eficientes e corretas para o seu tipo.
using System;
using System.Collections.Generic;
public struct Point : IEquatable<Point>
{
public int X, Y;
public Point(int x, int y) { X = x; Y = y; }
public bool Equals(Point other) => X == other.X && Y == other.Y;
public override bool Equals(object obj) => obj is Point p && Equals(p);
public override int GetHashCode() => HashCode.Combine(X, Y);
}
public class Program
{
public static void Main()
{
var list = new List<Point> { new Point(0, 0), new Point(1, 1) };
Console.WriteLine(list.Contains(new Point(1, 1)));
}
}Tipos de referência e IEquatable<T>
As classes também podem implementar IEquatable<T>. O método Equals tipado evita uma conversão de tipo, e você trata null explicitamente para o parâmetro de referência.
using System;
public class Person : IEquatable<Person>
{
public string Name;
public Person(string name) { Name = name; }
public bool Equals(Person other) => other != null && other.Name == Name;
public override bool Equals(object obj) => Equals(obj as Person);
public override int GetHashCode() => Name?.GetHashCode() ?? 0;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Person("Ada").Equals(new Person("Ada")));
Console.WriteLine(new Person("Ada").Equals((Person)null));
}
}Encaminhando object.Equals para o método tipado
Um padrão claro é escrever a comparação uma única vez em Equals(T) e fazer com que object.Equals a delegue a esse método. Isso garante que ambos se comportem de forma idêntica.
using System;
public struct Id : IEquatable<Id>
{
public int Value;
public Id(int value) { Value = value; }
public bool Equals(Id other) => Value == other.Value;
public override bool Equals(object obj) => obj is Id other && Equals(other);
public override int GetHashCode() => Value;
}
public class Program
{
public static void Main()
{
object boxed = new Id(5);
Console.WriteLine(boxed.Equals(new Id(5)));
}
}Comparando vários campos
Para tipos com vários campos, compare todos eles em Equals. Duas instâncias são iguais somente se todos os campos relevantes coincidirem.
using System;
public struct DateRange : IEquatable<DateRange>
{
public int Start, End;
public DateRange(int start, int end) { Start = start; End = end; }
public bool Equals(DateRange other) => Start == other.Start && End == other.End;
public override bool Equals(object obj) => obj is DateRange d && Equals(d);
public override int GetHashCode() => HashCode.Combine(Start, End);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new DateRange(1, 5).Equals(new DateRange(1, 5)));
Console.WriteLine(new DateRange(1, 5).Equals(new DateRange(1, 6)));
}
}Combinando com operadores
Combine IEquatable<T> com == e != para que os usuários possam comparar usando qualquer uma das sintaxes, sempre com a mesma comparação tipada como base.
using System;
public struct Money : IEquatable<Money>
{
public decimal Amount;
public Money(decimal a) { Amount = a; }
public bool Equals(Money other) => Amount == other.Amount;
public override bool Equals(object obj) => obj is Money m && Equals(m);
public override int GetHashCode() => Amount.GetHashCode();
public static bool operator ==(Money a, Money b) => a.Equals(b);
public static bool operator !=(Money a, Money b) => !a.Equals(b);
}
public class Program
{
public static void Main()
{
Console.WriteLine(new Money(9.99m) == new Money(9.99m));
}
}Os registros implementam isso automaticamente
Um record C# gera IEquatable<T>, Equals baseado em valor e GetHashCode para você. Quando a igualdade por valor é tudo de que você precisa, um registro elimina código repetitivo.
using System;
public record Point(int X, int Y);
public class Program
{
public static void Main()
{
var a = new Point(1, 2);
var b = new Point(1, 2);
Console.WriteLine(a.Equals(b));
Console.WriteLine(a == b);
}
}Quando implementar manualmente
Implemente IEquatable<T> manualmente quando precisar de regras de igualdade personalizadas, como nomes que não diferenciam maiúsculas de minúsculas ou a ignorância de determinados campos, que um registro não consegue expressar diretamente.
using System;
public class CaseInsensitiveTag : IEquatable<CaseInsensitiveTag>
{
public string Name;
public CaseInsensitiveTag(string name) { Name = name; }
public bool Equals(CaseInsensitiveTag other)
=> other != null && string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase);
public override bool Equals(object obj) => Equals(obj as CaseInsensitiveTag);
public override int GetHashCode() => Name?.ToLowerInvariant().GetHashCode() ?? 0;
}
public class Program
{
public static void Main()
{
Console.WriteLine(new CaseInsensitiveTag("Red").Equals(new CaseInsensitiveTag("RED")));
}
}Experimente você mesmo
Implemente IEquatable<T> para um pequeno tipo de referência e encaminhe todos os caminhos de igualdade pelo método tipado.
using System;
using System.Collections.Generic;
public class Coordinate : IEquatable<Coordinate>
{
public int Lat, Lng;
public Coordinate(int lat, int lng) { Lat = lat; Lng = lng; }
public bool Equals(Coordinate other) => other != null && other.Lat == Lat && other.Lng == Lng;
public override bool Equals(object obj) => Equals(obj as Coordinate);
public override int GetHashCode() => HashCode.Combine(Lat, Lng);
}
public class Program
{
public static void Main()
{
var set = new HashSet<Coordinate> { new Coordinate(10, 20) };
Console.WriteLine(set.Contains(new Coordinate(10, 20)));
}
}Verificação rápida
Relembre o benefício de IEquatable
Recapitulação
IEquatable<T> fornece igualdade com segurança de tipos.
- Fornece
Equals(T other), evitando o encaixotamento para estruturas e conversões de tipo para classes. - As coleções dão preferência a ele para pesquisas corretas e eficientes.
- Encaminhe
object.Equalse os operadores pelo método tipado. - Os registros o implementam automaticamente; implemente-o manualmente para regras personalizadas.
Perguntas Frequentes
A aula “Implementando IEquatable” é grátis?
Sim — o texto completo de “Implementando IEquatable” é 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 4 aulas no total.
O que vou aprender em “Implementando IEquatable”?
Forneça igualdade com segurança de tipos usando Equals. 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 1 de 4.
Quanto tempo leva a aula “Implementando IEquatable”?
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
- Implementando IEquatable
- Substituindo GetHashCode
- Implementando IComparable
- IComparer para classificação personalizada