Membuat class pembawa data biasanya berarti menulis banyak kode seremonial: constructor, property, method Equals, GetHashCode, dan ToString. Semua kode itu berulang di setiap class data dan mudah tertinggal sebagian. Kata kunci record menyatakan tipe referensi pembawa data sekaligus memerintahkan compiler membangkitkan anggota-anggota tersebut. Record class tetap berada di heap seperti class, tetapi perbandingannya bekerja berbasis isi.

Deklarasi Positional Record #

Bentuk paling ringkas record memakai parameter posisional. Contoh berikut mendefinisikan record Pesanan lalu membandingkan dua instance dengan isi sama:

csharp
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);

Console.WriteLine(pesananA);
Console.WriteLine(pesananA == pesananB);
Console.WriteLine(ReferenceEquals(pesananA, pesananB));

Pesanan salinan = pesananA;
Console.WriteLine(ReferenceEquals(pesananA, salinan));

Output yang Dihasilkan:

text
Pesanan { Id = 1, Produk = Kopi Gayo, Harga = 45000 }
True
False
True

Mari kita bedah baris demi baris:

  1. public record Pesanan(int Id, string Produk, int Harga);: satu baris deklarasi menghasilkan constructor berparameter, tiga property init-only bernama sama dengan parameternya, serta seluruh anggota kesetaraan.
  2. Console.WriteLine(pesananA): method ToString yang dibangkitkan compiler menampilkan nama tipe beserta seluruh nilai property, sehingga isi record mudah diperiksa saat debugging.
  3. pesananA == pesananB: operator == yang dibangkitkan membandingkan isi kedua record; hasilnya True meskipun keduanya dibuat terpisah dengan new.
  4. ReferenceEquals(pesananA, pesananB): method ini membandingkan alamat object; dua instance terpisah di heap menghasilkan False, bukti bahwa record tetap tipe referensi.
  5. Pesanan salinan = pesananA;: assignment menyalin alamat, bukan isinya; ReferenceEquals menegaskan keduanya menunjuk object yang sama dengan hasil True.

Anggota yang Dibangkitkan Compiler #

AnggotaPerilaku
Property init-onlyNama dan tipe mengikuti parameter posisional; nilai hanya diisi saat pembuatan object
ToString()Menampilkan nama tipe dan seluruh property beserta nilainya
Equals dan GetHashCodeMembandingkan tipe runtime dan seluruh property
Operator == dan !=Memanggil perbandingan berbasis isi
Deconstruct()Membongkar record menjadi variable-variable terpisah

Sintaks parameter posisional bukan satu-satunya bentuk record. Kita juga dapat menulis record dengan isi class biasa, lalu memilih property yang ingin bersifat init-only. Compiler mengenali kedua bentuk dan tetap membangkitkan anggota kesetaraan yang sama:

csharp
public record Produk
{
    public string Nama { get; init; } = "";
    public int Stok { get; init; }
}

Property init-only memberi jaminan penting bagi record: object yang telah dibuat tidak dapat diubah isinya dari luar, sekalipun kode pemakainya menyimpan alamat object tersebut. Imutabilitas inilah yang membuat perbandingan berbasis isi pada record tetap bermakna sepanjang masa pakai object.