Dua object Produk berisi Id dan Nama yang sama persis. Apakah keduanya sama? Untuk int, jawabannya jelas: 5 == 5 bernilai True. Untuk class, C# perlu kita beri tahu makna “sama”, karena jawaban bawaannya hanya membandingkan alamat memori.
Perilaku Bawaan: Perbandingan Reference #
Semua class mewarisi method Equals() dari class Object. Versi bawaannya mengembalikan True hanya bila kedua variable menunjuk object yang sama persis di heap. Operator == pada variable bertipe class berperilaku serupa. Dua object dengan isi identik tetap dianggap berbeda selama keduanya dibuat dua kali dengan new. Perbandingan seperti ini cocok bila object memang unik, misalnya object koneksi atau layanan tunggal; masalah muncul ketika object mewakili data yang nilainya bisa setara.
Mengoverride Equals dan GetHashCode #
Class Produk berikut mengganti makna kesetaraan menjadi perbandingan isi, dan sekaligus mengimplementasikan IEquatable<Produk>:
public class Produk : IEquatable<Produk>
{
public int Id { get; set; }
public string Nama { get; set; }
public Produk(int id, string nama)
{
Id = id;
Nama = nama;
}
public bool Equals(Produk? other)
{
if (other is null)
{
return false;
}
return Id == other.Id && Nama == other.Nama;
}
public override bool Equals(object? obj)
{
return Equals(obj as Produk);
}
public override int GetHashCode()
{
return HashCode.Combine(Id, Nama);
}
}
Produk produkA = new Produk(1, "Kopi Gayo");
Produk produkB = new Produk(1, "Kopi Gayo");
Produk produkC = new Produk(2, "Teh Melati");
Console.WriteLine(produkA == produkB);
Console.WriteLine(produkA.Equals(produkB));
Console.WriteLine(produkA.Equals(produkC));
Console.WriteLine(produkA.GetHashCode() == produkB.GetHashCode());Output yang Dihasilkan:
False
True
False
TrueMari kita bedah baris demi baris:
: IEquatable<Produk>: Interface ini menuntut methodEqualsyang menerima parameter bertipeProduk, sehingga pembanding bekerja langsung pada tipe yang tepat tanpa cast.public bool Equals(Produk? other): Tanda?menyatakan parameter bolehnull; bila bernilainull, method mengembalikanFalse.return Id == other.Id && Nama == other.Nama;: Kesetaraan didefinisikan dari isi, bukan alamat;produkAdanprodukBdianggap sama meskipun keduanya dibuat dengannew.public override bool Equals(object? obj): Versi lama dariObjectdidelegasikan ke versi bertipe kuat agar perilaku tetap konsisten di semua jalur pemanggilan.public override int GetHashCode(): Method ini menghasilkan angka ringkas dari isi object; dua object yangEquals-nyaTruewajib punya kode yang sama.produkA == produkB: HasilnyaFalsekarena operator==tetap membandingkan reference.
Kontrak yang perlu diingat: Equals yang mengembalikan True menuntut GetHashCode yang sama, dan perbandingan isi sebaiknya diterapkan pada kedua method sekaligus agar koleksi seperti Dictionary bekerja dengan benar.
Ringkasan alat perbandingan yang dipakai pada bab ini:
| Alat | Membandingkan | Catatan |
|---|---|---|
== | Reference untuk class | Perlu operator overload agar membandingkan isi |
Equals(object?) | Sesuai versi override | Didelegasikan ke IEquatable<T> pada contoh |
IEquatable<T>.Equals | Isi object bertipe sama | Versi bertipe kuat, tanpa cast |
GetHashCode() | Angka ringkas dari isi | Wajib konsisten dengan Equals |