Menu

C# Ternary Operatörü (?:): Sözdizimi, Tipler, İç İçe Kullanım ve ??

C# koşul operatörü condition ? a : b iki değerden birini seçer. Nasıl değerlendirildiği, iki dalın neden ortak bir tipe ihtiyaç duyduğu (CS0173) ve bunu düzelten cast, iç içe ternary'ler, string interpolation'da parantezler ve ?? ile ?.'nın ne zaman daha iyi ifade ettiği.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Genellikle ternary operatörü denen koşul operatörü, tek bir ifadede iki değer arasında seçim yapar: condition ? valueIfTrue : valueIfFalse.

Çıktı:

0 items, shipping 4.99
1 item, shipping 4.99
5 items, shipping 0

Koşul bir bool olmalıdır. Değerlendirildikten sonra iki daldan yalnızca biri çalışır; diğeri hiç değerlendirilmez. Bu, operatörü list.Count > 0 ? list[0] : "empty" gibi korumalı erişimler için güvenli kılar; boş bir listede list[0]'ı değerlendirmek istisna fırlatırdı.

Ternary ile if/else

Ternary bir ifadedir: atadığınız, geçirdiğiniz ya da döndürdüğünüz bir değer üretir. Bir if ifadesi ise deyimler çalıştırır. Bu iki metot aynı şeyi yapar:

// 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";

İki dal da aynı türden kısa değerler olduğunda ternary kullanın. Bir dal birkaç deyim çalıştırıyorsa, yan etkileri varsa ya da koşul tüm satır rahatça sığmayacak kadar uzunsa if kullanın.

Ternary yalnızca eylem gerçekleştiren bir if'in yerini alamaz. Bu derlenmez:

stock > 0 ? Ship(order) : Refund(order);
// error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement

else olmadan ternary de yoktur: ? ve : her zaman zorunludur, çünkü ifadenin iki durumda da bir değeri olmalıdır.

İki Dal da Ortak Bir Tip Gerektirir

Derleyici tüm ifadenin tipini iki dalından çıkarır. Dallardan biri örtük olarak diğerinin tipine dönüşmelidir. İkisi de dönüşmediğinde CS0173 alırsınız:

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'

Çözüm, dallardan birini istediğiniz tipe cast etmektir, böylece diğeri ona dönüşür:

Çıktı:

no discount
7
3.5

points / 2.0 : 0 cast gerektirmez: 0 bir int'tir ve örtük olarak double'a dönüşür, bu yüzden ifade bir double'dır.

C# 9 hedef tiplemeyi ekledi: ifade bildirilmiş bir tipe atandığında derleyici o tipi kullanır. int? discount = isMember ? 10 : null; C# 9 ve sonrasında derlenir. var ile hedef tip yoktur, bu yüzden var discount = isMember ? 10 : null; her sürümde hâlâ başarısız olur.

Öncelik ve Parantezler

Koşul operatörünün önceliği çok düşüktür; +, == ve &&'den düşüktür. Bu a > b ? a : b'de kullanışlıdır, string birleştirmenin içinde ise şaşırtıcıdır:

Console.WriteLine("Status: " + isActive ? "on" : "off");
// error CS0029: Cannot implicitly convert type 'string' to 'bool'

Derleyici koşulu bir string olan "Status: " + isActive olarak okur. Ternary'nin etrafındaki parantezler sorunu çözer: "Status: " + (isActive ? "on" : "off").

String interpolation'ın kendi tuzağı vardır. { } içinde iki nokta bir biçim belirtecini başlatır ({price:F2}), bu yüzden çıplak bir ternary parser'ın kafasını karıştırır. Onu parantez içine alın:

Çıktı:

2 users online
You have 1 unread message
Status: online

İç İçe Ternary'ler

Operatör sağdan birleşimlidir, bu yüzden a ? x : b ? y : z, a ? x : (b ? y : z) olarak gruplanır. Satır başına bir koşulla yerleştirilmiş küçük bir zincir okunabilirdir:

Çıktı:

512 B
20 KB
5 MB

İki üç seviyeyi aşınca ya da koşullar farklı şeyleri test ettiğinde if/else if'e ya da bir switch expression'a geçin. Doğru dalın içinde iç içe kullanım (a ? (b ? x : y) : z) takip etmesi ilk zorlaşan sürümdür.

?? ve ?. Yaygın Ternary'lerin Yerini Alır

Birçok ternary yalnızca null'ı ele almak için vardır. C#'ta bunlar için daha kısa operatörler vardır:

TernaryKısa biçimAnlamı
name != null ? name : "guest"name ?? "guest"null olduğunda yedek
customer != null ? customer.Email : nullcustomer?.Emailnull'a tahammül eden üye erişimi
c != null && c.Address != null ? c.Address.City : "unknown"c?.Address?.City ?? "unknown"ikisi birlikte
value != null ? value : throw new ArgumentNullException(...)value ?? throw new ArgumentNullException(...)hızlı başarısız ol

Çıktı:

Lena from Berlin
guest from unknown
guest from unknown

Bir ternary'nin iki dalından biri olarak bir throw ifadesine de izin verilir: int age = input >= 0 ? input : throw new ArgumentOutOfRangeException(nameof(input));.

ref Koşulu

C# 7.2'den beri bir ternary iki değer yerine iki değişken arasında seçim yapabilir ve sonuç üzerinden atama yapabilirsiniz:

// 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

İki dal da aynı tipteki değişkenlere ref olmalıdır. Uygulama kodunda nadirdir; esas olarak büyük struct'larla ya da dizilerle onları kopyalamadan çalışan, performansa duyarlı kod için vardır.

Sıkça Sorulan Sorular

C#'ta ternary operatörü nedir?

C#'ın üç işlenenli tek operatörü olan condition ? valueIfTrue : valueIfFalse koşul operatörüdür. Koşulu değerlendirir, sonra iki değerden tam olarak birini değerlendirip döndürür: string label = age >= 18 ? "adult" : "minor";.

C#'ta else olmadan ternary kullanılabilir mi?

Hayır. Hem ? hem de : kısmı zorunludur, çünkü ifade her zaman bir değer üretmelidir. Yalnızca bir koşul sağlandığında bir şey yapmak istiyorsanız bir if ifadesi kullanın. Ternary tek başına bir deyim olarak da duramaz: x > 0 ? A() : B(); CS0201 hatasıdır.

Neden "Type of conditional expression cannot be determined" hatası alıyorum?

İki dalın ortak bir tipi yoktur; örneğin var x = found ? 42 : null; (int ve null) ya da found ? 1 : "none". Bir tip var olsun diye dallardan birini cast edin: found ? (int?)42 : null. C# 9'dan beri bildirilen bir hedef tip de işe yarar: int? x = found ? 42 : null; derlenir, ama var hâlâ başarısız olur.

Ternary operatörü string interpolation içinde nasıl kullanılır?

Onu parantez içine alın: $"{(count == 1 ? "item" : "items")}". Parantez olmadan : bir biçim belirtecinin başlangıcı olarak okunur ve kod derlenmez.

C#'ta ternary operatörleri iç içe kullanılabilir mi?

Evet. Operatör sağdan birleşimlidir, bu yüzden a ? x : b ? y : z, a ? x : (b ? y : z) demektir. Ayrı satırlara yerleştirilmiş tek seviyelik iç içelik iyi okunur; daha derin zincirler bir if/else if zinciri ya da switch expression olarak daha anlaşılırdır.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA