C#9m READ12 Haziran 2026

C# Pattern Matching ve Switch Expression: Modern C# Sözdizimi

switch expression, is pattern, when guard ve property pattern.

C# 8'den itibaren eklenen pattern matching özellikleri, switch ifadelerini ve koşullu kontrolleri dramatik biçimde kısaltıyor. Uzun if-else zincirleri, açık cast'lar ve null kontrolleri artık tek satır ifadelere indirgeniyor. Bu makale, C# pattern matching'in tüm varyantlarını karşılaştırmalı örneklerle anlatıyor.

Switch Expression: Temel Sözdizimi

C# 8 öncesi switch statement ile C# 8+ switch expression karşılaştırması:

// CSHARP //
// Eski yol — verbose
string GetStatusText(OrderStatus status)
{
    switch (status)
    {
        case OrderStatus.Pending:
            return "Beklemede";
        case OrderStatus.Processing:
            return "İşleniyor";
        case OrderStatus.Shipped:
            return "Kargoda";
        case OrderStatus.Delivered:
            return "Teslim Edildi";
        default:
            return "Bilinmiyor";
    }
}
 
// C# 8+ — switch expression
string GetStatusText(OrderStatus status) => status switch
{
    OrderStatus.Pending    => "Beklemede",
    OrderStatus.Processing => "İşleniyor",
    OrderStatus.Shipped    => "Kargoda",
    OrderStatus.Delivered  => "Teslim Edildi",
    _                      => "Bilinmiyor",
};

Type Pattern

// CSHARP //
// Eski yol
double GetArea(Shape shape)
{
    if (shape is Circle c)
        return Math.PI * c.Radius * c.Radius;
    if (shape is Rectangle r)
        return r.Width * r.Height;
    if (shape is Triangle t)
        return 0.5 * t.Base * t.Height;
    throw new ArgumentException("Bilinmeyen şekil");
}
 
// Type pattern ile
double GetArea(Shape shape) => shape switch
{
    Circle    c => Math.PI * c.Radius * c.Radius,
    Rectangle r => r.Width * r.Height,
    Triangle  t => 0.5 * t.Base * t.Height,
    _           => throw new ArgumentException($"Bilinmeyen şekil: {shape.GetType().Name}"),
};

Property Pattern

// CSHARP //
record Point(int X, int Y);
record Order(decimal Amount, string Country, bool IsPremium);
 
// Property pattern — nesne özelliklerine göre eşleşme
string GetQuadrant(Point p) => p switch
{
    { X: > 0, Y: > 0 } => "I. Kadran",
    { X: < 0, Y: > 0 } => "II. Kadran",
    { X: < 0, Y: < 0 } => "III. Kadran",
    { X: > 0, Y: < 0 } => "IV. Kadran",
    { X: 0 }            => "Y Ekseni",
    { Y: 0 }            => "X Ekseni",
    _                   => "Orijin",
};
 
// Sipariş indirimi hesabı
decimal CalculateDiscount(Order order) => order switch
{
    { IsPremium: true, Amount: > 1000 }              => order.Amount * 0.20m,
    { IsPremium: true }                               => order.Amount * 0.10m,
    { Country: "TR", Amount: > 500 }                 => order.Amount * 0.05m,
    { Amount: > 2000 }                               => order.Amount * 0.08m,
    _                                                 => 0m,
};

Positional Pattern (Deconstruction)

// CSHARP //
record struct Point2D(double X, double Y)
{
    // Deconstruct metodu pattern matching için gerekli
    public void Deconstruct(out double x, out double y) => (x, y) = (X, Y);
}
 
string Classify(Point2D p) => p switch
{
    (0, 0)           => "Orijin",
    (var x, 0)       => $"X ekseni: {x}",
    (0, var y)       => $"Y ekseni: {y}",
    (var x, var y) when x == y => "Diyagonal",
    (var x, var y)   => $"Nokta ({x:F1}, {y:F1})",
};
 
// Tuple pattern
string Classify(bool isAdmin, bool isActive) => (isAdmin, isActive) switch
{
    (true, true)   => "Aktif Admin",
    (true, false)  => "Pasif Admin",
    (false, true)  => "Aktif Kullanıcı",
    (false, false) => "Pasif Kullanıcı",
};

Relational Pattern (C# 9)

// CSHARP //
string GetTemperatureCategory(double celsius) => celsius switch
{
    < -20            => "Dondurucu Soğuk",
    >= -20 and < 0   => "Soğuk",
    >= 0   and < 15  => "Serin",
    >= 15  and < 25  => "Ilık",
    >= 25  and < 35  => "Sıcak",
    >= 35            => "Kavurucu Sıcak",
};
 
// HTTP durum kodu açıklaması
string GetHttpCategory(int statusCode) => statusCode switch
{
    >= 100 and < 200 => "Bilgilendirme",
    >= 200 and < 300 => "Başarılı",
    >= 300 and < 400 => "Yönlendirme",
    >= 400 and < 500 => "İstemci Hatası",
    >= 500 and < 600 => "Sunucu Hatası",
    _                => "Geçersiz Kod",
};

List Pattern (C# 11)

// CSHARP //
string DescribeList(int[] numbers) => numbers switch
{
    []           => "Boş liste",
    [var tek]    => $"Tek eleman: {tek}",
    [var a, var b] => $"İki eleman: {a}, {b}",
    [1, 2, ..]   => "1 ve 2 ile başlıyor",
    [.., 0]      => "Sıfırla bitiyor",
    [var ilk, .., var son] => $"İlk: {ilk}, Son: {son}",
};
 
// Gerçek kullanım — CSV satırı parse
string? ParseCsvLine(string[] parts) => parts switch
{
    ["DELETE", var id, ..]           => $"Sil: {id}",
    ["INSERT", var tablo, var deger] => $"Ekle {tablo}: {deger}",
    ["UPDATE", var id, var alan, var yeniDeger] => $"Güncelle {id}.{alan} = {yeniDeger}",
    _                                => null,
};

Nested Pattern: Karmaşık Kurallar

// CSHARP //
record Address(string Country, string City);
record Customer(string Name, Address Address, bool IsPremium);
 
decimal GetShippingCost(Customer customer) => customer switch
{
    { IsPremium: true }                          => 0m,  // premium ücretsiz
    { Address: { Country: "TR", City: "İstanbul" } } => 5m,
    { Address: { Country: "TR" } }               => 10m,
    { Address: { Country: "DE" or "FR" or "NL" } } => 25m,
    _                                             => 50m,
};

Pattern Matching is/when ile

// CSHARP //
// is ile type ve property pattern
object obj = GetValue();
 
if (obj is string { Length: > 0 } str)
    Console.WriteLine($"String: {str}");
 
if (obj is List<int> { Count: >= 3 } list)
    Console.WriteLine($"Liste, {list.Count} eleman");
 
// when guard — switch içinde ek koşul
string Classify(int n) => n switch
{
    0                      => "Sıfır",
    < 0                    => "Negatif",
    var x when x % 2 == 0 => $"Çift: {x}",
    var x                  => $"Tek: {x}",
};

Performans ve Derleme

Derleyici, switch expression'ları karmaşık bir karar ağacına dönüştürür. Basit enum switch'ler jump table (O(1)) olarak derlenir; type pattern'lar is kontrol zinciri olarak. Pattern exhaustiveness (tüm durumların kapsanması) derleme zamanında kontrol edilir — _ eklemezsen uyarı alırsın.

// CSHARP //
// Exhaustive pattern — compiler tüm enum değerlerini kontrol eder
// Yeni enum değeri eklenirse derleme uyarısı/hatası alırsın
string GetName(DayOfWeek day) => day switch
{
    DayOfWeek.Monday    => "Pazartesi",
    DayOfWeek.Tuesday   => "Salı",
    DayOfWeek.Wednesday => "Çarşamba",
    DayOfWeek.Thursday  => "Perşembe",
    DayOfWeek.Friday    => "Cuma",
    DayOfWeek.Saturday  => "Cumartesi",
    DayOfWeek.Sunday    => "Pazar",
    // _ yok — eksik enum varsa CS8509 uyarısı
};

Özet

C# pattern matching; switch expression (C# 8), property pattern, relational pattern (C# 9) ve list pattern (C# 11) katmanlarıyla gelişti. Temel kural: is null kontrolü + type check için, switch expression koşul dallanması için, property pattern veri sınıflarını deconstruct etmek için kullanılır. Null'a karşı { } not-null pattern ve when guard ile neredeyse tüm koşullu mantık tek expression'a sığar.