Menu

C# switch Expression: Sözdizimi, Desenler, Discard ve when

C# 8 switch expression, case ve break yerine desen kollarıyla bir değeri bir sonuca çevirir. Sözdizimi, _ discard'ı, property, tuple ve ilişkisel desenler, and/or/not, when korumaları, kapsayıcılık uyarıları ve SwitchExpressionException, çalıştırılabilir C# 7 karşılıklarıyla.

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

Bir switch expression bir girdi değerini bir sonuca eşler. C# 8'de eklendi ve her case'i yalnızca bir şey döndüren ya da atayan bir switch ifadesinin yaygın kalıbının yerini alır:

// C# 8 and later
string StatusText(int code) => code switch
{
    200 => "OK",
    301 or 302 => "Redirect",   // 'or' needs C# 9
    404 => "Not Found",
    >= 500 => "Server Error",   // relational patterns need C# 9
    _ => "Unknown"
};

Yukarıdan aşağıya okuyun: switch'ten önceki değer sırayla her kola karşı test edilir ve deseni eşleşen ilk kol sonucu sağlar. case, break ya da default anahtar kelimesi yoktur; _ (discard deseni) her şeyle eşleşir ve yedek görevi görür.

C# 7'de aynı eşleme, her case'te return bulunan küçük bir metottaki switch ifadesidir:

Çıktı:

200 OK
302 Redirect
404 Not Found
503 Server Error
418 Unknown

Expression biçimi daha kısadır, çünkü esas olarak her kol tek satırdır ve metot gövdesi ortadan kalkar. Aynı zamanda bir ifadedir, bu yüzden bir değerin durabileceği her yerde durabilir: bir argüman, bir interpolation boşluğu, bir return, bir alan başlatıcısı.

Sözdizimi Kuralları

var result = input switch
{
    pattern1 => value1,
    pattern2 when condition => value2,
    _ => fallback
};
  • Önce girdi, sonra switch gelir. Bu, statement biçiminin tersidir.
  • Her kol pattern => expression şeklindedir. Sağ taraf tek bir ifade olmalıdır; daha fazla mantık için bir metot çağırın.
  • Kollar virgülle ayrılır. Son koldan sonra fazladan bir virgüle izin verilir.
  • Hepsi bir ifadedir, bu yüzden onu kullanan bir deyim kapanış süslü parantezinden sonra ; ile biter.
  • Tüm kollar ortak bir tipte değer üretmelidir. var x = n switch { 0 => "zero", _ => 0 }; derlenmez (CS8506, en iyi tip yok). C# 9'dan beri bildirilen bir hedef tip sorunu çözer: object x = n switch { 0 => "zero", _ => 0 }; derlenir.
  • Her kol bir değer üretmelidir, bu yüzden bir kol Console.WriteLine gibi void bir metot çağıramaz ve bir switch expression tek başına bir deyim olarak duramaz (CS0201). Eylemler için switch ifadesini (statement) kullanın.
  • Bir kol değer üretmek yerine istisna fırlatabilir: _ => throw new ArgumentOutOfRangeException(nameof(input)).
  • Derleyici, daha önceki bir kol onu zaten kapsadığı için hiç ulaşılamayacak bir kolu CS8510 hatasıyla reddeder: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match. Özel kolları genel olanlardan önce koyun.

İlişkisel ve Mantıksal Desenler (C# 9)

C# 9 desen olarak <, <=, >, >='yi ve and, or ve not birleştiricilerini ekledi. Aralık tablolarını bir şartname gibi okunur hale getirirler:

// C# 9 and later
string Grade(int score) => score switch
{
    < 0 or > 100 => throw new ArgumentOutOfRangeException(nameof(score)),
    >= 90 => "A",
    >= 80 => "B",
    >= 70 => "C",
    >= 60 => "D",
    _ => "F"
};

string AgeGroup(int age) => age switch
{
    < 13 => "child",
    >= 13 and <= 19 => "teen",
    _ => "adult"
};

bool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';

Kollar sırayla denendiği için >= 80 yalnızca 90'ın altındaki puanları görür. İlişkisel desenler sağda yalnızca sabit alır; bir değişkenle karşılaştırmak için bir when koruması kullanın. Bir aralık tablosunun C# 7 karşılığı bir if zinciridir:

Çıktı:

95 -> A
83 -> B
71 -> C
64 -> D
12 -> F

not en çok not null olarak kullanılır: x is not null ya da not null => x.Name kolu.

Property Desenleri

Bir property deseni bir nesnenin üyeleri üzerinde eşleşir: { Property: pattern, ... }. Bir switch expression ile birleştiğinde iş kurallarını bir && koşulları zinciri olmadan ifade eder:

// C# 8 and later
decimal ShippingCost(Order order) => order switch
{
    { Total: >= 100m } => 0m,                       // relational inside: C# 9
    { Country: "US", Express: true } => 15m,
    { Country: "US" } => 5m,
    { Express: true } => 30m,
    null => throw new ArgumentNullException(nameof(order)),
    _ => 12m
};

Kolun eşleşmesi için listelenen her property eşleşmelidir. Boş bir property deseni { } null olmayan her değerle eşleşir. C# 10, iç içe üyeler için genişletilmiş property desenlerini ekledi: { Customer: { Address: { Country: "US" } } } yerine { Customer.Address.Country: "US" }.

Tuple Desenleri

Bir tuple üzerinde switch yapmak aynı anda birkaç değeri eşleştirir; bir karar tablosunu ifade etmenin temiz yolu budur:

// C# 9 and later (the 'or' pattern)
string Winner(string a, string b) => (a, b) switch
{
    ("rock", "scissors") or ("scissors", "paper") or ("paper", "rock") => "player 1",
    var (x, y) when x == y => "draw",
    _ => "player 2"
};

var (x, y), tuple'ı when korumasının karşılaştırabileceği iki değişkene ayrıştırır. C# 7'de olağan yedek, değerleri tek bir anahtarda birleştirmek ya da sonuçlardan oluşan bir dictionary kullanmaktır:

Çıktı:

player 1
player 2
draw

Tip Desenleri ve when

Bir kol çalışma zamanı tipini test edip bir değişken bağlayabilir, bir when cümlesi de desen sözdiziminin ifade edemediği herhangi bir koşulu ekler:

// C# 8 and later
double Area(Shape shape) => shape switch
{
    Circle c => Math.PI * c.Radius * c.Radius,
    Rectangle r when r.Width == r.Height => r.Width * r.Width,
    Rectangle r => r.Width * r.Height,
    null => throw new ArgumentNullException(nameof(shape)),
    _ => throw new NotSupportedException(shape.GetType().Name)
};

C# 7 sürümü, değişkeni aynı şekilde bağlayan is tip desenini bir if zincirinde kullanır:

Çıktı:

Circle: 12.57
Rectangle: 13.50

Kapsayıcılık ve SwitchExpressionException

Bir switch expression her girdi için bir değer üretmelidir. Derleyici hiçbir kolun eşleşmediği girdiler görebildiğinde uyarır:

warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered.

Bu bir hata değil uyarıdır, bu yüzden kod yine derlenir. Çalışma zamanında eşleşmeyen bir değer gelirse ifade, mesajı eşleşmeyen değerle biten (Unmatched value was 3.) System.Runtime.CompilerServices.SwitchExpressionException fırlatır.

Enum'lar özel bir durumdur. Her adlandırılmış üyenin bir kolu olsa bile bir enum değişkeni herhangi bir tamsayıyı tutabilir ((Size)3), bu yüzden derleyici "adlandırılmamış bir enum değeri" için CS8524 bildirir:

// C# 8 and later
enum Size { Small, Medium, Large }

string Code(Size s) => s switch
{
    Size.Small => "S",
    Size.Medium => "M",
    Size.Large => "L",
    // warning CS8524 without the next arm
    _ => throw new ArgumentOutOfRangeException(nameof(s))
};

Yararlı bir istisna fırlatan açık bir _ kolu ekleyin. Bu, varsayımı belgeler, uyarıyı susturur ve kötü bir değer ortaya çıkarsa SwitchExpressionException'dan daha anlaşılır bir hata verir.

Alternatif Olarak Dictionary

Kollar saf sabit-değer çiftleriyse ve tablo büyüyebilir ya da yapılandırmadan gelebilirse, bir Dictionary aynı işi her C# sürümünde yapar ve çalışma zamanında oluşturulabilir:

Çıktı:

19.00
11.50
0

Bilinmeyen bir ülke 0m oranı alır. Bir decimal çarpımı, iki işleninin toplamı kadar ondalık basamağa sahiptir; 100m * 0.19m'nin 19.00, sıfır oranın ise 0 yazdırmasının nedeni budur.

Switch Expression ile Switch İfadesi

switch ifadesiswitch expression
Şu sürümden beriC# 1C# 8
Değer üretirhayırevet
Dal başına sözdizimicase X: ... break;X => value,
Yedekdefault:_ =>
Dal başına birkaç ifadeevethayır, bir metot çağırın
Kapsayıcılık uyarısıhayırevet (CS8509)
Çalışma zamanında eşleşme yokhiçbir şey çalışmazSwitchExpressionException

İki biçim de aynı desenleri alır (tipler, sabitler, property'ler, tuple'lar, ilişkisel), bu yüzden birini öğrenmek diğerini de öğretir. Seçim şekille ilgilidir: bir değer expression'dan, bir eylemler dizisi statement'tan geçer.

Sıkça Sorulan Sorular

C#'ta switch expression nedir?

C# 8'de eklenen bir switch expression bir değere değerlendirilir: string text = code switch { 200 => "OK", 404 => "Not Found", _ => "Unknown" };. Girdi switch anahtar kelimesinden önce gelir, her kol pattern => result şeklindedir, kollar virgülle ayrılır ve case, break ya da default anahtar kelimesi yoktur.

C# switch expression'da default case nedir?

Discard deseni _ her şeyle eşleşir, bu yüzden son kol olarak _ => "Unknown" default rolünü oynar. Hepsini yakalayan bir kol olmadan, bazı girdiler kapsanmadığında derleyici uyarır (CS8509) ve çalışma zamanında eşleşmeyen bir değer SwitchExpressionException fırlatır.

Bir switch expression kolunda birden fazla değer nasıl eşleştirilir?

C# 9'daki or desenini kullanın: "sat" or "sun" => "weekend". Aralıklar için ilişkisel desenleri and ile birleştirin: >= 13 and <= 19 => "teen". C# 8'de değerleri aynı sonuca sahip ayrı kollar olarak listelerdiniz.

C# switch expression'da when kullanılabilir mi?

Evet. Bir kol deseninden sonra bir koruma ekleyebilir: Order o when o.Total > 100 => 0m. Kol yalnızca desen eşleşirse ve when koşulu doğruysa eşleşir; aksi halde değerlendirme sonraki kolla devam eder.

switch expression mı kullanmalıyım, switch ifadesi mi?

Her dal yalnızca bir değer üretiyorsa expression'ı kullanın; örneğin bir durumu bir etikete eşlemek ya da bir fiyat hesaplamak. Dallar birkaç ifade çalıştırıyorsa, yan etkileri varsa ya da bir döngüden çıkması gerekiyorsa ifadeyi (statement) kullanın. Expression ayrıca statement'ın vermediği kapsayıcılık uyarılarını da verir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA