Menu

Operator Ternary C# (?:): Sintaks, Tipe, Bersarang, dan ??

Operator kondisional C# condition ? a : b memilih salah satu dari dua nilai. Cara evaluasinya, kenapa kedua cabang butuh tipe yang sama (CS0173) dan cast yang memperbaikinya, ternary bersarang, tanda kurung di interpolasi string, serta kapan ?? dan ?. lebih tepat dipakai.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

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:

TernaryBentuk lebih pendekArti
name != null ? name : "guest"name ?? "guest"nilai cadangan saat null
customer != null ? customer.Email : nullcustomer?.Emailakses 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.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai