Section ini telah memperkenalkan empat cara mendefinisikan tipe: class, struct, record class, dan record struct. Keempatnya menghasilkan tipe yang sah, tetapi semantik penyalinan, penyimpanan, dan kesetaraannya berbeda. Pilihan yang tepat membuat kode lebih mudah dipahami; pilihan yang tergesa menimbulkan kekeliruan salinan data yang sulit dilacak. Bab penutup ini merangkum perbedaannya, lalu memberikan panduan memilih.

Demo Ringkas Empat Tipe #

Contoh berikut menguji keempat tipe dengan skenario yang sama: menyalin variable, mengubah salinannya, dan membandingkan dua instance berisi nilai sama:

csharp
public class TitikClass { public int X; public int Y; }
public struct TitikStruct { public int X; public int Y; }
public record TitikRecordClass(int X, int Y);
public record struct TitikRecordStruct(int X, int Y);

TitikClass titikClass = new TitikClass { X = 1, Y = 2 };
TitikClass salinanClass = titikClass;
salinanClass.X = 99;

TitikStruct titikStruct = new TitikStruct { X = 1, Y = 2 };
TitikStruct salinanStruct = titikStruct;
salinanStruct.X = 99;

TitikRecordClass recordA = new TitikRecordClass(1, 2);
TitikRecordClass recordB = new TitikRecordClass(1, 2);
TitikRecordStruct recordStructA = new TitikRecordStruct(1, 2);
TitikRecordStruct recordStructB = new TitikRecordStruct(1, 2);

Console.WriteLine(titikClass.X);
Console.WriteLine(titikStruct.X);
Console.WriteLine(recordA == recordB);
Console.WriteLine(recordStructA == recordStructB);

Output yang Dihasilkan:

text
99
1
True
True

Mari kita bedah hasilnya:

  1. titikClass.X menampilkan 99: salinanClass menunjuk object yang sama dengan titikClass, sehingga perubahan pada salinan ikut terbaca dari variable asalnya.
  2. titikStruct.X menampilkan 1: salinanStruct membawa salinan data tersendiri, sehingga perubahan salinan tidak menyentuh variable asalnya.
  3. recordA == recordB menghasilkan True: record class membandingkan isi; dua instance terpisah dengan nilai sama dianggap sama.
  4. recordStructA == recordStructB menghasilkan True: record struct menggabungkan semantik nilai dan kesetaraan berbasis isi.

Panduan Memilih Tipe #

Tabel berikut merangkum keputusan yang dapat dijadikan pegangan:

KebutuhanPilihanAlasan
Object dengan identitas, perilaku kompleks, atau pewarisanClassReference type dengan masa pakai panjang di heap
Data kecil berperan sebagai satu nilai, dibuat dalam jumlah besarStruct atau record structTanpa alokasi heap, penyalinan cepat
Data immutable yang dibandingkan berdasarkan isiRecord class atau record structKesetaraan dan ToString dibangkitkan compiler
Data sekali pakai di dalam satu methodTuple atau anonymous typeDeklarasi ringkas tanpa tipe baru
Banyak pilihan yang menyala bersamaanFlags enumSatu nilai menyimpan kombinasi bit

Beberapa aturan praktis menuntun pilihan tersebut:

  1. Mulailah dari class atau record class untuk tipe domain; pindah ke struct hanya bila data benar-benar kecil dan berperan sebagai nilai.
  2. Pilih record bila kesetaraan berbasis isi dibutuhkan; hindari menulis Equals manual hanya untuk menggantikan yang sudah dibangkitkan compiler.
  3. Jadikan struct atau record struct bersifat readonly agar risiko perubahan pada salinan tidak mungkin terjadi.
  4. Pertahankan aturan domain di dalam value object, bukan di method yang tersebar di luar tipe.