Kesetaraan berbasis isi adalah alasan utama record diciptakan. Pertanyaannya, kapan persisnya dua record dianggap sama, dan apa saja yang compiler periksa? Record membandingkan tipe runtime terlebih dahulu, lalu membandingkan setiap property satu per satu. Aturan tersebut membuat record aman dipakai sebagai kunci pencarian di koleksi, sekaligus menyimpan satu kejutan pada pewarisan yang perlu kita kenali.
Kesetaraan Berbasis Isi #
Contoh berikut menguji beberapa skenario kesetaraan pada record Pesanan, termasuk pencarian di List:
public record Pesanan(int Id, string Produk, int Harga);
Pesanan pesananA = new Pesanan(1, "Kopi Gayo", 45000);
Pesanan pesananB = new Pesanan(1, "Kopi Gayo", 45000);
Pesanan pesananC = new Pesanan(1, "Kopi Gayo", 50000);
Console.WriteLine(pesananA == pesananB);
Console.WriteLine(pesananA == pesananC);
Console.WriteLine(pesananA.GetHashCode() == pesananB.GetHashCode());
List<Pesanan> antrean = new List<Pesanan> { pesananA };
Console.WriteLine(antrean.Contains(new Pesanan(1, "Kopi Gayo", 45000)));Output yang Dihasilkan:
True
False
True
TrueMari kita bedah baris demi baris:
pesananA == pesananB: seluruh property bernilai sama, sehingga perbandingan menghasilkanTrue; kedua record tidak perlu dibuat dari object yang sama.pesananA == pesananC: satu property berbeda, yaituHarga, sudah cukup membuat keseluruhan perbandingan menghasilkanFalse.pesananA.GetHashCode() == pesananB.GetHashCode():GetHashCodedihitung dari isi property; dua record yang setara wajib menghasilkan kode hash yang sama, dan hasilnyaTrue.antrean.Contains(...):ListmemanggilEqualssaat mencari; record baru dengan isi sama ditemukan meskipun dibuat terpisah dari yang tersimpan.
Pemeriksaan Tipe Runtime #
Method Equals yang dibangkitkan compiler juga membandingkan tipe runtime kedua object melalui anggota internal bernama EqualityContract. Contoh berikut membuktikan akibatnya:
public record PesananEkspres(int Id, string Produk, int Harga, int BiayaKurir)
: Pesanan(Id, Produk, Harga);
Pesanan biasa = new Pesanan(1, "Kopi Gayo", 45000);
PesananEkspres ekspres = new PesananEkspres(1, "Kopi Gayo", 45000, 0);
Console.WriteLine(biasa == ekspres);Output yang Dihasilkan:
Falseekspres mewarisi semua nilai dasar yang sama dan BiayaKurir bernilai 0. Meskipun demikian, tipe runtime PesananEkspres berbeda dari Pesanan, sehingga perbandingan menghasilkan False.
Cara Kerja Method Equals yang Dibangkitkan #
Method Equals hasil bangunan compiler menjalankan pemeriksaan berurutan berikut:
- Pemeriksaan
null: parameter yang bernilainulllangsung menghasilkanFalse. - Pemeriksaan tipe: method membandingkan
EqualityContractkedua object; tipe runtime yang berbeda langsung menghasilkanFalse. - Perbandingan property: setiap property dibandingkan satu per satu dengan operator kesetaraannya; satu property berbeda membuat keseluruhan hasil menjadi
False.
Compiler juga mengimplementasikan interface IEquatable<T> untuk tipe record tersebut, sehingga pembandingan tidak perlu melakukan cast dan bekerja cepat di dalam koleksi generik seperti List<T> maupun HashSet<T>. Manfaatnya terasa pada skenario pencarian: method Contains, IndexOf, dan Remove pada List memakai Equals yang sama dengan operator ==, sehingga hasil pencarian konsisten di semua jalur.