Operator null C#

Tip

Artikel ini adalah bagian dari bagian Dasar-Dasar untuk pengembang yang mengetahui setidaknya satu bahasa pemrograman dan mempelajari C#. Jika Anda baru menggunakan pemrograman, mulailah dengan tutorial Memulai terlebih dahulu. Untuk referensi operator lengkap, lihat Operator Akses Anggota dan Operator Null-Coalescing dalam referensi bahasa.

C# menyediakan beberapa operator yang membuat ringkas kode null-safe. Alih-alih menumpuk if (x != null) penjaga di seluruh kode Anda, operator ini memungkinkan Anda mengekspresikan akses null-safe, nilai fallback, dan pengujian null dalam satu ekspresi.

Artikel ini membahas ?. dan ?[] mengenai akses null-conditional, ?? null-coalescing, ??= penugasan null-coalescing, serta is null/is not null untuk pencocokan pola null.

Pengaksesan anggota dengan null-conditional ?.

Operator ?. mengakses anggota hanya ketika objek non-null. Ketika objek adalah null, seluruh ekspresi mengevaluasi ke null alih-alih melempar NullReferenceException:

string? name = null;

// Without ?., accessing a member on null throws NullReferenceException:
// int len = name.Length; // throws if name is null

// ?. returns null instead of throwing:
int? len = name?.Length;
Console.WriteLine(len.HasValue); // False

name = "C#";
Console.WriteLine(name?.Length); // 2

Operator ?.sirkuit pendek: ketika sisi kiri adalah null, semuanya di sebelah kanan dilewati. Tidak ada panggilan metode yang dijalankan dan tidak ada efek samping yang terjadi.

Anda dapat menautkan beberapa ?. operator dalam satu ekspresi. Rantai berhenti pada null yang pertama kali ditemuinya.

string? input = null;

// Chain ?. across multiple method calls — short-circuits at the first null:
string? upper = input?.Trim()?.ToUpperInvariant();
Console.WriteLine(upper ?? "(none)"); // (none)

input = "  hello  ";
Console.WriteLine(input?.Trim()?.ToUpperInvariant()); // HELLO

Akses pengindeks bersyarat null ?[]

Operator ?[] menerapkan perilaku sirkuit pendek yang sama ke akses pengindeks dan array. Gunakan saat koleksi itu sendiri mungkin null:

string[]? tags = null;

// ?[] accesses an element only when the collection is non-null
string? first = tags?[0];
Console.WriteLine(first ?? "(none)"); // (none)

tags = ["csharp", "dotnet", "nullable"];
Console.WriteLine(tags?[0]);          // csharp

Operator rantai null-kondisional

Rantai beberapa operator ?. untuk menelusuri jalur referensi yang mungkin null. Terjadi korsleting pada rantai di posisi pertama null:

var order = new Order("ORD-001", null);

// Each ?. short-circuits when null: Customer is null, so Address and City are never accessed
string? city = order.Customer?.Address?.City;
Console.WriteLine(city ?? "(no city)"); // (no city)

var fullOrder = new Order("ORD-002",
    new Customer("Alice", new Address("123 Main St", "Springfield", "IL")));

Console.WriteLine(fullOrder.Customer?.Address?.City); // Springfield

Ketika Customer adalah null, baik Address maupun City tidak dievaluasi. Seluruh ekspresi mengembalikan nilai null.

Pemanggilan delegasi aman utas

?. menyediakan cara yang bersih dan aman untuk memanggil delegasi atau memicu acara. Ekspresi delegasi dievaluasi hanya sekali, sehingga tidak ada jendela bagi utas lain untuk berhenti berlangganan antara pemeriksaan null dan pemanggilan:

EventHandler? clicked = null;

// No subscribers — ?.Invoke does nothing instead of throwing NullReferenceException
clicked?.Invoke(null, EventArgs.Empty);

clicked += (_, _) => Console.WriteLine("Button clicked!");

// With a subscriber — ?.Invoke calls the handler
clicked?.Invoke(null, EventArgs.Empty);
// Output: Button clicked!

Pola ini menggantikan idiom yang lebih if (clicked != null) clicked(...) lama.

Operator penggabungan null ??

Operator ?? mengembalikan operand sebelah kirinya ketika operand tersebut tidak kosong (non-null), dan mengembalikan operand kanannya ketika operand sebelah kirinya adalah null. Gunakan untuk memberikan nilai default:

string? username = null;

// ?? returns the right-hand value when the left-hand is null
string display = username ?? "Guest";
Console.WriteLine(display); // Guest

username = "alice";
display  = username ?? "Guest";
Console.WriteLine(display); // alice

?? bersifat asosiatif kanan, jadi a ?? b ?? c dievaluasi sebagai a ?? (b ?? c). Nilai non-null pertama menang. Pola umum adalah menautkan ?. dengan ??: gunakan ?. untuk secara aman melintasi rantai yang mungkin null, lalu ?? untuk mengganti default jika rantai tersebut mengembalikan null. Untuk contoh lengkapnya, lihat Menggabungkan operator null.

Penugasan null-coalescing ??=

Operator ??= menetapkan nilai sebelah kanan ke variabel hanya ketika variabel adalah null. Gunakan untuk inisialisasi malas:

List<string>? cache = null;

// ??= assigns only when the variable is null
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

// cache is already non-null, so LoadData() isn't called again
cache ??= LoadData();
Console.WriteLine(cache.Count); // 3

static List<string> LoadData() => ["alpha", "beta", "gamma"];

Ekspresi sebelah kanan dievaluasi hanya ketika variabel adalah null. Ketika variabel sudah memiliki nilai, sisi kanan tidak dievaluasi sama sekali.

Penetapan Nilai Kondisional Null (C# 14)

Mulai dari C# 14, Anda dapat menggunakan ?. dan ?[] sebagai target penugasan. Penugasan hanya dieksekusi ketika objek di sebelah kiri tidak null:

AppConfig? config = new AppConfig();

// Assigns only when config is non-null (C# 14)
config?.Theme = "dark";
Console.WriteLine(config?.Theme); // dark

AppConfig? missing = null;
missing?.Theme = "light";                         // no-op: missing is null
Console.WriteLine(missing?.Theme ?? "(no config)"); // (no config)

Sisi kanan dievaluasi hanya ketika sisi kiri diketahui non-null.

Pencocokan pola null: is null dan is not null

Pengujian pola-pola is null dan is not null untuk memeriksa apakah sebuah ekspresi adalah null:

string? input = null;

// is null is the preferred test — unaffected by operator overloading
if (input is null)
{
    Console.WriteLine("No input provided.");
}

// == null also works, but a custom == operator can change its behavior
if (input == null)
{
    Console.WriteLine("Still no input.");
}

Lebih suka is null daripada == null untuk pemeriksaan null. Operator == dapat kelebihan beban, artinya x == null mungkin mengembalikan true bahkan jika x tidak null jika tipe tersebut mendefinisikan operator kesetaraan kustom. Pola is null selalu menguji referensi null aktual, terlepas dari kelebihan beban operator.

string? value = "hello";

if (value is not null)
{
    Console.WriteLine(value.ToUpper()); // HELLO
}

Menggabungkan operator null

Dalam praktiknya, Anda sering menggabungkan beberapa operator ini. Satu ekspresi dapat dengan aman melintasi grafik objek dalam, menerapkan fallback, lalu menjaga hasilnya:

Order? order = GetPendingOrder();

// Chain ?. for safe traversal, ?? for a fallback, is null for a clear guard
string city = order?.Customer?.Address?.City ?? "unknown";

if (order is null)
{
    Console.WriteLine("No pending order.");
}
else
{
    Console.WriteLine($"Shipping to: {city}");
}
// Output: No pending order.

Operator pengampunan null !

Operator ! postfix menghilangkan peringatan nullable. Tambahkan ! untuk memberi tahu pengkompilasi "ekspresi ini jelas bukan null." Operator tidak berpengaruh pada waktu proses. Ini hanya mempengaruhi analisis status null kompilator.

string? name = FindUser("alice");

// Use ! only when you have information the compiler doesn't.
// FindUser guarantees a non-null result for known usernames.
int length = name!.Length;
Console.WriteLine(length); // 5

Gunakan ! dengan hemat, dan hanya ketika Anda memiliki informasi yang tidak dimiliki oleh compiler. Contohnya termasuk pengujian yang sengaja lolos null untuk memvalidasi logika pemeriksaan argumen, atau memanggil metode yang kontraknya menjamin pengembalian non-null untuk input yang diketahui. Penggunaan berlebihan ! tidak sesuai dengan tujuan jenis referensi nullable. Untuk penjelasan lengkap, lihat Nullable Reference Types.

Baca juga