Nullable Reference Type

Model keamanan null modern, penanda ?, dan disiplin pemeriksaan null.

Daftar isi

Topik ini membahas nullable reference type, yaitu model keamanan null modern pada C# yang memindahkan kesalahan pemakaian null dari waktu program berjalan ke waktu kompilasi. Nilai null, penanda ? pada tipe, dan disiplin pemeriksaan null dibahas berurutan dengan contoh yang dapat dijalankan. Setelah topik ini diselesaikan, variabel yang boleh kosong dan yang tidak boleh kosong dapat dipisahkan secara eksplisit dalam kode.

Null dan masalah yang ditimbulkannya#

Nilai null berarti sebuah variabel tidak merujuk ke objek apa pun. Pemanggilan metode pada variabel yang bernilai null tidak memiliki sasarannya, sehingga runtime memunculkan exception NullReferenceException dan program berhenti tidak wajar. Sebelum C# 8, variabel bertipe referensi bebas diisi null tanpa peringatan apa pun, sehingga banyak error semacam itu baru ditemukan saat program sudah berjalan.

Model nullable reference type mengubah kontrak tersebut. Tipe tanpa tanda ? dinyatakan tidak boleh bernilai null, sedangkan tipe dengan tanda ?, seperti string?, dinyatakan boleh kosong. Fitur ini aktif secara default pada proyek hasil dotnet new, termasuk pada contoh-contoh di jalur ini. Program berikut menunjukkan keduanya berdampingan.

Model ini mengatur tipe referensi saja. Variabel int atau double tidak pernah kosong karena tipe nilai (value type) selalu menyimpan sebuah nilai, sedangkan bentuk int? merupakan tipe lain yang memang dirancang menampung ketiadaan angka. Pembahasan di sini berfokus pada string? karena tipe referensi inilah yang paling sering ditemui pada tahap awal.

csharp Contoh: tipe biasa dan tipe nullable
string nama = "Budi";
string? hobi = null;

Console.WriteLine(nama.Length);
Console.WriteLine(hobi == null);

hobi = "bersepeda";
Console.WriteLine(hobi.Length);
text Keluaran
4
True
9

Deklarasi string? hobi = null; sah tanpa peringatan apa pun karena tipenya memang memperbolehkan null. Setelah hobi diisi string, properti Length dapat dipanggil seperti biasa. Pada tahap inilah kompilator bekerja lebih cerdas daripada sekadar membaca tipe, karena alur program juga dianalisis.

csharp Contoh: pemanggilan metode pada variabel yang masih null
// tidak-dijalankan
string? pesan = null;
Console.WriteLine(pesan.Length);

Baris terakhir memanggil metode pada variabel yang masih bernilai null. Kompilator menandainya dengan pesan warning CS8602: Dereference of a possibly null reference, dan bila tetap dijalankan, program berhenti dengan NullReferenceException. Contoh ini sengaja tidak dijalankan sampai selesai karena keluarannya berupa laporan exception, bukan keluaran program yang wajar.

Pemeriksaan null sebelum digunakan#

Disiplin inti model ini sederhana, yaitu pemeriksaan null dilakukan sebelum variabel nullable dipakai. Kompilator menganalisis alur eksekusi dan melacak hasil pemeriksaan tersebut. Setelah satu cabang kode membuktikan variabel tidak null, pemakaian di dalam cabang itu dianggap aman dan peringatan menghilang.

csharp Contoh: pemeriksaan dengan is null
string? pesan = null;

if (pesan is null)
{
    Console.WriteLine("Pesan belum diisi.");
}
text Keluaran
Pesan belum diisi.

Pola is null merupakan bentuk pemeriksaan yang disarankan karena tidak mungkin tertukar dengan penugasan. Bentuk pesan == null juga sah dan menghasilkan nilai bool yang sama. Apabila variabel diberi nilai sebelum pemakaiannya, kompilator menganggap pemakaiannya aman tanpa perlu pemeriksaan tambahan, sebagaimana hobi pada contoh pertama di atas.

Kebalikannya juga sah, yaitu pesan != null, dan analisis alur mengikuti hasil pemeriksaan itu dengan cara yang sama. Di dalam cabang yang membuktikan variabel tidak null, pemakaian apa pun dianggap aman, sedangkan cabang else-nya kembali dianggap mungkin kosong. Analisis ini berlaku per cabang kode, sehingga pemeriksaan tidak perlu diulang pada baris yang sudah terlindungi olehnya.

Operator bantu null#

C# menyediakan dua operator yang merapikan pemeriksaan null. Operator ?? yang disebut null-coalescing menghasilkan operan kanan bila operan kirinya bernilai null. Operator ini menggantikan blok pemeriksaan yang hanya berisi penentuan nilai cadangan.

csharp Contoh: nilai cadangan dengan operator ??
string? catatan = null;
string tampilan = catatan ?? "(kosong)";

Console.WriteLine(tampilan);

catatan = "kembali dari peminjaman buku";
Console.WriteLine(catatan ?? "(kosong)");
text Keluaran
(kosong)
kembali dari peminjaman buku

Operator ?. yang disebut null-conditional memanggil anggota hanya bila operan kirinya tidak null, dan menghasilkan null bila sebaliknya. Gabungan ?. dan ?? menghasilkan pola pendek yang sangat umum untuk membaca properti dari nilai yang mungkin kosong.

csharp Contoh: operator ?. gabung dengan ??
string? alias = null;
int panjang = alias?.Length ?? 0;

Console.WriteLine(panjang);
text Keluaran
0

Bila alias bernilai null, ekspresi alias?.Length tidak memanggil properti apa pun dan menghasilkan null, sehingga nilai cadangan 0 yang dipakai. Kedua operator ini tidak menggantikan disiplin pemeriksaan, melainkan mempersingkat bentuknya.

Kesalahan umum#

  • Mengabaikan peringatan CS8602. Warning ini berarti ada jalur eksekusi yang memanggil anggota pada nilai null, sehingga error NullReferenceException tinggal menunggu. Tambahkan pemeriksaan is null atau nilai cadangan ?? pada jalur tersebut.
  • Menandai semua string dengan ?. Tipe nullable seharusnya hanya dipakai bila ketiadaan nilai memang bermakna, misalnya masukan yang boleh dikosongkan. Penanda ? pada setiap variabel menghapus informasi desain yang justru ingin dijaga.
  • Memeriksa null setelah variabel dipakai. Pemeriksaan yang ditulis setelah baris pemakaian tidak menyelamatkan jalur yang sudah lewat, dan kompilator tetap memberi peringatan pada baris pemakaian tersebut. Letakkan pemeriksaan sebelum pemakaian pertama.

Ringkasan#

  • Model nullable reference type memisahkan tipe yang dijamin tidak null dan tipe yang boleh null melalui penanda ?, dan model ini aktif secara default pada proyek baru.
  • Kompilator menganalisis alur program, sehingga pemakaian yang sudah didahului pemeriksaan is null dianggap aman.
  • Operator ?? menyediakan nilai cadangan, sedangkan ?. memanggil anggota hanya bila operan kirinya tidak null.
  • Pemakaian anggota pada variabel nullable yang belum diperiksa menghasilkan warning CS8602 pada waktu kompilasi dan NullReferenceException pada waktu berjalan.

Referensi#