Tipe nilai seperti int selalu menyimpan sebuah angka; kita tidak bisa menugaskan null kepadanya. Padahal data bisnis sering punya keadaan belum diisi: stok cadangan belum ditetapkan atau tanggal kirim belum dipilih. Trik memakai nilai sentinel seperti -1 menimbulkan ambiguitas karena angka itu bisa jadi data yang sah. Nullable value types menjawab kebutuhan itu dengan membungkus tipe nilai agar menerima null.
Masalah Tipe Nilai Tanpa Keadaan Kosong #
Variabel int wajib berisi angka, sedangkan kebutuhan nyata menuntut tiga keadaan: berisi angka, berisi nol, dan belum diisi. Sentinel menggabungkan makna angka sah dengan penanda kosong, sehingga pembaca kode harus menebak. Struct Nullable<T> menyelesaikannya dengan menyimpan nilai bersama penanda keberadaan nilai.
Mekanisme Nullable<T> #
Deklarasi int? adalah gula sintaks untuk Nullable<int>. Pembungkus ini menyimpan dua hal: nilai di property Value dan penanda bool di property HasValue. Anotasi T? hanya berlaku untuk tipe nilai; untuk tipe referensi, tanda tanya menjadi nullable reference types pada bab berikutnya. Saat pembungkus berisi nilai di-boxing, runtime men-boxing nilai di dalamnya, bukan struct pembungkusnya.
Contoh: Stok Cadangan Gudang #
int? stokCadangan = null;
int? stokNol = 0;
Console.WriteLine($"Stok cadangan ada nilai: {stokCadangan.HasValue}");
Console.WriteLine($"Stok nol ada nilai: {stokNol.HasValue}");
Console.WriteLine($"Cadangan + GetValueOrDefault: {stokCadangan.GetValueOrDefault(0)}");
stokCadangan = 40;
int stokWajib = stokCadangan.Value;
Console.WriteLine($"Setelah restok: {stokWajib}");
Console.WriteLine($"Operator ??: {stokCadangan ?? 0}");
object hasilBoxing = stokWajib;
Console.WriteLine($"Boxing nilai 40 menjadi: {hasilBoxing.GetType().Name}");
object? boxingKosong = (int?)null;
Console.WriteLine($"Boxing int? null menghasilkan: {boxingKosong ?? "null"}");Output yang Dihasilkan:
Stok cadangan ada nilai: False
Stok nol ada nilai: True
Cadangan + GetValueOrDefault: 0
Setelah restok: 40
Operator ??: 40
Boxing nilai 40 menjadi: Int32
Boxing int? null menghasilkan: nullMari kita bedah baris demi baris:
- Baris 1 (
int? stokCadangan = null;): Compiler membuatNullable<int>yang kosong, sehinggaHasValuebernilaiFalse. - Baris 2 (
int? stokNol = 0;): Nol adalah nilai sah di dalam pembungkus, sehinggaHasValuebernilaiTrue; keadaan ini berbeda dengan kosong. - Baris 6 (
GetValueOrDefault(0)): Method mengembalikan nilai bila ada, atau fallback0bila kosong, tanpa risiko exception. - Baris 8-9 (
stokCadangan = 40; ... .Value): Penugasan mengisi pembungkus, laluValuemengambilintdi dalamnya untuk variabelstokWajib. - Baris 14-18 (dua baris boxing): Runtime men-boxing
intmenjadiInt32, sedangkan pembungkus kosong di-boxing menjadinullreference.
Anggota Penting Nullable<T> #
| Anggota | Perilaku |
|---|---|
HasValue | True bila pembungkus berisi nilai |
Value | Mengembalikan nilai; melempar exception bila kosong |
GetValueOrDefault(fallback) | Mengembalikan nilai atau argumen fallback bila kosong |