Analisis alur compiler menilai kode dari luar, sedangkan niat desain API terkadang lebih kaya dari yang terlihat: setter yang menolak null, method yang mengisi field sebelum dipakai, atau fungsi Try-prefixed yang menjamin hasil di kondisi tertentu. Atribut nullability dari namespace System.Diagnostics.CodeAnalysis menuliskan niat itu agar compiler menilai pemanggil dengan benar.
Lima Atribut Utama #
| Atribut | Pernyataan |
|---|---|
[AllowNull] | Input boleh null meski tipenya non-nullable |
[DisallowNull] | Input tidak boleh null meski tipenya nullable |
[NotNullWhen(bool)] | Parameter out/bool terisi bila return bernilai tertentu |
[NotNullIfNotNull(arg)] | Return terisi bila argumen bernama terisi |
[MemberNotNull(member)] | Method menjamin anggota tertentu sudah terisi saat kembali |
Contoh Terpadu #
using System.Diagnostics.CodeAnalysis;
public class Profil
{
private string nama = "";
[AllowNull]
public string Nama
{
get => nama;
set => nama = value ?? "(belum diisi)";
}
private string? judul;
[MemberNotNull(nameof(judul))]
public void SiapkanJudul()
{
judul = "Struk Pesanan";
}
public int PanjangJudul()
{
SiapkanJudul();
return judul.Length;
}
}
public class Resi
{
[DisallowNull]
public string? Nomor { get; set; }
}
public class LayananKupon
{
public static bool CobaAmbil(string produk, [NotNullWhen(true)] out string? kode)
{
if (produk == "Kopi Gayo")
{
kode = "HEMAT20";
return true;
}
kode = null;
return false;
}
public static string? TandaiSiap([NotNullIfNotNull("kode")] string? kode)
{
return kode is null ? null : $"{kode}-SIAP";
}
}
Profil profil = new Profil();
profil.Nama = null;
Console.WriteLine($"Nama: {profil.Nama}");
Console.WriteLine($"Panjang judul: {profil.PanjangJudul()}");
Resi resi = new Resi();
resi.Nomor = "JX-88231";
Console.WriteLine($"Resi: {resi.Nomor}");
if (LayananKupon.CobaAmbil("Kopi Gayo", out string? kode))
{
Console.WriteLine($"Kode: {kode.ToUpperInvariant()}");
}
Console.WriteLine($"Status: {LayananKupon.TandaiSiap("ORD-4001")}");Output yang Dihasilkan:
Nama: (belum diisi)
Panjang judul: 13
Resi: JX-88231
Kode: HEMAT20
Status: ORD-4001-SIAPMari kita bedah anggota kuncinya:
[AllowNull]padaNama: Penugasanprofil.Nama = nullsah di mata compiler, sedangkan setter menggantinya dengan teks bawaan; property tetap terbaca sebagaistringnon-nullable.[MemberNotNull(nameof(judul))]: SetelahSiapkanJudul()dipanggil, compiler menganggapjudulterisi, sehinggajudul.LengthdiPanjangJudulbebas warning.[DisallowNull]padaNomor: Tipestring?mengizinkan pembacaan kosong, tetapi penugasannulldari luar ditegur compiler.[NotNullWhen(true)]padaCobaAmbil: Di dalam blokifyang lolos,kodedijamin terisi, sehinggakode.ToUpperInvariant()bebas warning.[NotNullIfNotNull("kode")]padaTandaiSiap: Pemanggil dengan argumen non-nullable menerima return non-nullable tanpa pemeriksaan tambahan.
Warning yang Diredam Atribut #
Probe berikut menugaskan null ke property beranotasi [DisallowNull] dan membaca hasil out tanpa [NotNullWhen] (path project dipangkas):
Program.cs(4,14): warning CS8625: Cannot convert null literal to non-nullable reference type.
Program.cs(8,23): warning CS8602: Dereference of a possibly null reference.CS8625 muncul karena [DisallowNull] menolak null pada input, dan CS8602 muncul karena tanpa [NotNullWhen] compiler tidak menjamin parameter out terisi di dalam blok if.