Operator kondisional, yang biasa disebut operator ternary, memilih di antara dua nilai dalam satu ekspresi: condition ? valueIfTrue : valueIfFalse.
Output:
0 items, shipping 4.99
1 item, shipping 4.99
5 items, shipping 0
Kondisinya harus bertipe bool. Setelah kondisi dievaluasi, hanya satu dari dua cabang yang dijalankan; cabang lainnya tidak pernah dievaluasi. Karena itu operator ini aman untuk akses yang dijaga seperti list.Count > 0 ? list[0] : "empty", karena mengevaluasi list[0] pada list kosong akan melempar exception.
Ternary versus if/else
Ternary adalah ekspresi: ia menghasilkan nilai yang kamu simpan ke variabel, kirim sebagai argumen, atau kembalikan. Pernyataan if menjalankan pernyataan. Dua method ini melakukan hal yang sama:
// with if/else
static string Status(int stock)
{
if (stock > 0)
return "in stock";
else
return "sold out";
}
// with the ternary
static string Status(int stock) => stock > 0 ? "in stock" : "sold out";
Pakai ternary saat kedua cabang berupa nilai pendek dengan jenis yang sama. Pakai if saat sebuah cabang menjalankan beberapa pernyataan, punya efek samping, atau saat kondisinya cukup panjang sehingga seluruh baris tidak lagi nyaman dibaca.
Ternary tidak bisa menggantikan if yang hanya melakukan aksi. Kode ini tidak bisa dikompilasi:
stock > 0 ? Ship(order) : Refund(order);
// error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
Ternary tanpa else juga tidak ada: ? dan : selalu wajib, karena ekspresinya harus punya nilai di kedua kasus.
Kedua cabang butuh tipe yang sama
Compiler menentukan tipe seluruh ekspresi dari kedua cabangnya. Salah satu cabang harus bisa dikonversi secara implisit ke tipe cabang lainnya. Kalau tidak ada yang bisa, kamu mendapat CS0173:
var discount = isMember ? 10 : null;
// error CS0173: Type of conditional expression cannot be determined because
// there is no implicit conversion between 'int' and '<null>'
var label = inStock ? 1 : "none";
// error CS0173: ... between 'int' and 'string'
Solusinya adalah melakukan cast pada salah satu cabang ke tipe yang kamu inginkan, sehingga cabang lainnya dikonversi ke tipe itu:
Output:
no discount
7
3.5
points / 2.0 : 0 tidak butuh cast: 0 bertipe int, yang dikonversi secara implisit ke double, jadi ekspresinya bertipe double.
C# 9 menambahkan target typing: saat ekspresi disimpan ke variabel dengan tipe yang dideklarasikan, compiler memakai tipe itu. int? discount = isMember ? 10 : null; bisa dikompilasi di C# 9 dan sesudahnya. Dengan var tidak ada tipe target, jadi var discount = isMember ? 10 : null; tetap gagal di semua versi.
Prioritas operator dan tanda kurung
Operator kondisional punya prioritas yang sangat rendah, lebih rendah dari +, == dan &&. Ini memudahkan di a > b ? a : b, tetapi mengejutkan di dalam penggabungan string:
Console.WriteLine("Status: " + isActive ? "on" : "off");
// error CS0029: Cannot implicitly convert type 'string' to 'bool'
Compiler membaca kondisinya sebagai "Status: " + isActive, yaitu sebuah string. Tanda kurung di sekitar ternary memperbaikinya: "Status: " + (isActive ? "on" : "off").
Interpolasi string punya jebakannya sendiri. Di dalam { }, titik dua memulai format specifier ({price:F2}), jadi ternary tanpa tanda kurung membingungkan parser. Bungkus dengan tanda kurung:
Output:
2 users online
You have 1 unread message
Status: online
Ternary bersarang
Operator ini asosiatif kanan, jadi a ? x : b ? y : z dikelompokkan sebagai a ? x : (b ? y : z). Rantai kecil yang ditulis satu kondisi per baris masih mudah dibaca:
Output:
512 B
20 KB
5 MB
Lebih dari dua atau tiga tingkat, atau saat kondisinya menguji hal yang berbeda, beralihlah ke if/else if atau switch expression. Sarang di dalam cabang true (a ? (b ? x : y) : z) adalah bentuk yang paling cepat jadi sulit diikuti.
?? dan ?. menggantikan ternary yang umum
Banyak ternary ada hanya untuk menangani null. C# punya operator yang lebih pendek untuk itu:
| Ternary | Bentuk lebih pendek | Arti |
|---|---|---|
name != null ? name : "guest" | name ?? "guest" | nilai cadangan saat null |
customer != null ? customer.Email : null | customer?.Email | akses member yang aman dari null |
c != null && c.Address != null ? c.Address.City : "unknown" | c?.Address?.City ?? "unknown" | gabungan keduanya |
value != null ? value : throw new ArgumentNullException(...) | value ?? throw new ArgumentNullException(...) | langsung gagal (fail fast) |
Output:
Lena from Berlin
guest from unknown
guest from unknown
Ekspresi throw juga boleh dipakai sebagai salah satu cabang ternary: int age = input >= 0 ? input : throw new ArgumentOutOfRangeException(nameof(input));.
Kondisional ref
Sejak C# 7.2, ternary bisa memilih di antara dua variabel, bukan dua nilai, dan kamu bisa menyimpan nilai lewat hasilnya:
// C# 7.2 and later
int wins = 0, losses = 0;
bool won = true;
ref int counter = ref (won ? ref wins : ref losses);
counter++; // increments wins
Kedua cabang harus berupa ref ke variabel dengan tipe yang sama. Fitur ini jarang dipakai di kode aplikasi; fungsinya terutama untuk kode yang sensitif terhadap performa, yang bekerja dengan struct atau array besar tanpa menyalinnya.
Pertanyaan yang sering diajukan
Apa itu operator ternary di C#?
Operator ternary adalah operator kondisional condition ? valueIfTrue : valueIfFalse, satu-satunya operator C# dengan tiga operand. Operator ini mengevaluasi kondisi, lalu mengevaluasi dan mengembalikan tepat satu dari dua nilai: string label = age >= 18 ? "adult" : "minor";.
Bisakah ternary dipakai tanpa else di C#?
Tidak. Bagian ? dan : sama-sama wajib, karena ekspresinya harus selalu menghasilkan nilai. Kalau kamu hanya ingin melakukan sesuatu saat kondisi terpenuhi, pakai pernyataan if. Ternary juga tidak bisa berdiri sendiri sebagai pernyataan: x > 0 ? A() : B(); menghasilkan error CS0201.
Kenapa muncul error "Type of conditional expression cannot be determined"?
Kedua cabang tidak punya tipe yang sama, misalnya var x = found ? 42 : null; (int dan null) atau found ? 1 : "none". Lakukan cast pada salah satu cabang agar tipenya ada: found ? (int?)42 : null. Sejak C# 9, tipe target yang dideklarasikan juga berhasil: int? x = found ? 42 : null; bisa dikompilasi, tetapi var tetap gagal.
Bagaimana cara memakai operator ternary di dalam interpolasi string?
Bungkus dengan tanda kurung: $"{(count == 1 ? "item" : "items")}". Tanpa tanda kurung, : dibaca sebagai awal format specifier dan kodenya tidak bisa dikompilasi.
Bisakah operator ternary dibuat bersarang di C#?
Bisa. Operator ini asosiatif kanan, jadi a ? x : b ? y : z berarti a ? x : (b ? y : z). Satu tingkat sarang yang ditulis di baris terpisah masih mudah dibaca; rantai yang lebih dalam lebih jelas sebagai rantai if/else if atau switch expression.