22 Mayıs 2025

C#'ta Desen Eşleştirme

Modern C#, koşullu mantığı ele alma şeklimizde sessiz bir devrim geçirdi. Tür kontrollerinin ve değer karşılaştırmalarının uzun if-else zincirleri veya beceriksiz switch ifadeleri gerektirdiği günler geride kaldı. Özellikle C# 8.0'dan bu yana gelişmiş desen eşleştirme yeteneklerinin tanıtılması, geliştiricilerin kontrol akışını yazma şeklini temelden değiştirdi; kodu aynı anda daha anlamlı, daha özlü ve daha güvenli hale getirdi.

C# Desen Eşleştirme ile Kontrol Akışını Geliştirme

C#'ta desen eşleştirme, bir ifadeyi test etmek ve bu ifade belirli bir desenle eşleştiğinde eylemleri gerçekleştirmek için özlü bir sözdizimi sunar. Geliştiricilerin, türü, değeri, özellikleri veya hatta karmaşık nesnelerin yapısı da dahil olmak üzere çeşitli kriterlere göre değerleri test etmelerini sağlar. Bu yetenek esas olarak is ifadesi ve switch ifadesi (veya switch deyimi) aracılığıyla ortaya çıkar. Temel tür kontrolü daha önce var olsa da, C# 8.0 daha zengin bir desen sözlüğü sunarak, faydalarını ve günlük kodlama pratikleri üzerindeki etkisini önemli ölçüde genişletti. Bu geliştirme, etkili C# switch desen eşleştirme ve C# if desen eşleştirme için çok önemlidir; uzun koşullu mantığı, kompakt ve anlaşılır yapılar haline getirir.

Mevcut temel desen türlerinden bazılarını ve bunların yaygın programlama görevlerini nasıl basitleştirdiğini, faydalarını gösteren açık C# desen eşleştirme örnekleri sunarak keşfedelim.

Pratik C# Desen Eşleştirme Örnekleri

Desen eşleştirmenin gerçek gücü, geleneksel yaklaşımlarla karşılaştırıldığında belirginleşir. Geliştiriciler, kod okunabilirliği ve özlülüğünde önemli gelişmeler elde ederler.

Tanımlama Deseni

Tanımlama deseni, bir ifadenin çalışma zamanı türünü kontrol eder ve eşleşirse, sonucu yeni bir değişkene atar. Bu, birçok senaryoda açık tür dönüştürme ve null kontrolleri ihtiyacını ortadan kaldırır.

Öncesi:

public void ProcessAssetOld(object asset)
{
    if (asset is SoftwareLicense)
    {
        SoftwareLicense license = (SoftwareLicense)asset;
        Console.WriteLine($"Software License: {license.ProductName}, Expiration: {license.ExpirationDate.ToShortDateString()}");
    }
    else if (asset is HardwareComponent)
    {
        HardwareComponent hardware = (HardwareComponent)asset;
        Console.WriteLine($"Hardware Component: {hardware.ComponentName}, Serial: {hardware.SerialNumber}");
    }
    else
    {
        Console.WriteLine("Unknown asset type.");
    }
}

public class SoftwareLicense { public string ProductName { get; set; } public DateTime ExpirationDate { get; set; } }
public class HardwareComponent { public string ComponentName { get; set; } public string SerialNumber { get; set; } }

Sonrası (Tanımlama Deseni kullanarak):

public void ProcessAssetNew(object asset)
{
    if (asset is SoftwareLicense license)
    {
        Console.WriteLine($"Software License: {license.ProductName}, Expiration: {license.ExpirationDate.ToShortDateString()}");
    }
    else if (asset is HardwareComponent hardware)
    {
        Console.WriteLine($"Hardware Component: {hardware.ComponentName}, Serial: {hardware.SerialNumber}");
    }
    else
    {
        Console.WriteLine("Unknown asset type.");
    }
}

license ve hardware değişkenleri, yalnızca desen eşleşirse kapsamda olur ve atanır, bu da tür güvenliğini artırır ve olası çalışma zamanı hatalarını azaltır.

Tür Deseni

Tanımlama desenine benzer şekilde, tür deseni bir ifadenin çalışma zamanı türünü kontrol eder. Genellikle, desenin kendisi için yeni bir değişken bildiriminin kesinlikle gerekli olmadığı switch ifadelerinde kullanılır.

Öncesi:

public decimal CalculateShippingCostOld(Shipment shipment)
{
    if (shipment == null)
        throw new ArgumentNullException(nameof(shipment));
    if (shipment.GetType() == typeof(StandardShipment))
        return 5.00m;
    if (shipment.GetType() == typeof(ExpressShipment))
        return 15.00m;
    if (shipment.GetType() == typeof(InternationalShipment))
        return 25.00m;
    return 0.00m; // Default for unknown types
}

public abstract class Shipment { }
public class StandardShipment : Shipment { }
public class ExpressShipment : Shipment { }
public class InternationalShipment : Shipment { }

Sonrası (switch ifadesinde Tür Deseni kullanarak):

public decimal CalculateShippingCostNew(Shipment shipment) => shipment switch
{
    StandardShipment => 5.00m,
    ExpressShipment => 15.00m,
    InternationalShipment => 25.00m,
    null => throw new ArgumentNullException(nameof(shipment)),
    _ => 0.00m // Handle unknown shipment types
};

Bu, farklı türler için özlü C# switch case desen eşleştirmeyi gösterir.

Sabit Deseni

Bir sabit deseni, bir ifadenin sonucunun belirtilen bir sabit değere eşit olup olmadığını test eder. Bu, ayrık değer karşılaştırmalarını basitleştirir.

Öncesi:

public string GetOrderStateOld(OrderStatus status)
{
    if (status == OrderStatus.Pending)
        return "Order is awaiting processing.";
    else if (status == OrderStatus.Shipped)
        return "Order has been dispatched.";
    else if (status == OrderStatus.Delivered)
        return "Order has been delivered.";
    else if (status == OrderStatus.Cancelled)
        return "Order has been cancelled.";
    else
        return "Unknown order state.";
}

public enum OrderStatus { Pending, Shipped, Delivered, Cancelled, Returned }

Sonrası (Sabit Deseni kullanarak):

public string GetOrderStateNew(OrderStatus status) => status switch
{
    OrderStatus.Pending => "Order is awaiting processing.",
    OrderStatus.Shipped => "Order has been dispatched.",
    OrderStatus.Delivered => "Order has been delivered.",
    OrderStatus.Cancelled => "Order has been cancelled.",
    _ => "Unknown order state."
};

Bu, belirli C# dize desen eşleştirmelerini veya enum değerlerini ele almanın temiz bir yoludur.

İlişkisel Desenler

İlişkisel desenler, bir ifadenin sonucunu karşılaştırma operatörleri (<, >, <=, >=) kullanarak bir sabitle karşılaştırır. Bu, aralık kontrollerini çok daha okunabilir hale getirir.

Öncesi:

public string GetEmployeePerformanceLevelOld(int score)
{
    if (score < 50)
        return "Needs Improvement";
    else if (score >= 50 && score < 70)
        return "Meets Expectations";
    else if (score >= 70 && score < 90)
        return "Exceeds Expectations";
    else if (score >= 90)
        return "Outstanding";
    else
        return "Invalid Score"; // Should not happen with int, but for completeness
}

Sonrası (İlişkisel Desenler kullanarak):

public string GetEmployeePerformanceLevelNew(int score) => score switch
{
    < 50 => "Needs Improvement",
    >= 50 and < 70 => "Meets Expectations",
    >= 70 and < 90 => "Exceeds Expectations",
    >= 90 => "Outstanding",
    _ => "Invalid Score" // Catches any unexpected integer values
};

Bu, ilişkisel desenleri mantıksal desenlerle birleştirmenin gücünü C# desen eşleştirmesi için gösterir.

Özellik Deseni

Özellik deseni, bir ifadenin özelliklerini veya alanlarını iç içe desenlerle eşleştirmeye olanak tanır. Bu, nesnelerin durumunu incelemek için inanılmaz derecede kullanışlıdır.

Öncesi:

public decimal CalculateOrderDiscountOld(CustomerOrder order)
{
    if (order == null) return 0m;
    if (order.TotalAmount >= 500 && order.Customer.IsPremium)
    {
        return 0.15m; // 15% for premium customers with large orders
    }
    else if (order.TotalAmount >= 100)
    {
        return 0.05m; // 5% for general large orders
    }
    return 0m;
}

public class Customer { public bool IsPremium { get; set; } }
public class CustomerOrder { public decimal TotalAmount { get; set; } public Customer Customer { get; set; } }

Sonrası (Özellik Deseni kullanarak):

public decimal CalculateOrderDiscountNew(CustomerOrder order) => order switch
{
    { TotalAmount: >= 500, Customer.IsPremium: true } => 0.15m,
    { TotalAmount: >= 100 } => 0.05m,
    null => 0m,
    _ => 0m
};

Bu, güçlü C# özellik desen eşleştirmesini gösterir ve nesne durumu kontrollerini basitleştirir.

Konumsal Desen

Konumsal desenler, bir ifadenin sonucunu (Deconstruct metotları olan tuple'lar veya kayıtlar gibi) ayrıştırır ve ortaya çıkan değerleri iç içe desenlerle eşleştirir.

Öncesi:

public string DescribeTransactionOld(Transaction transaction)
{
    if (transaction.Type == TransactionType.Deposit && transaction.Amount > 1000)
        return "Large Deposit";
    else if (transaction.Type == TransactionType.Withdrawal && transaction.Amount > 500)
        return "Significant Withdrawal";
    else if (transaction.Type == TransactionType.Fee && transaction.Amount > 0)
        return "Applied Fee";
    else
        return "Standard Transaction";
}

public record Transaction(TransactionType Type, decimal Amount);
public enum TransactionType { Deposit, Withdrawal, Fee, Transfer }

Sonrası (Konumsal Desen kullanarak):

public string DescribeTransactionNew(Transaction transaction) => transaction switch
{
    (TransactionType.Deposit, > 1000m) => "Large Deposit",
    (TransactionType.Withdrawal, > 500m) => "Significant Withdrawal",
    (TransactionType.Fee, > 0m) => "Applied Fee",
    _ => "Standard Transaction"
};

Bu özlü biçim, ayrıştırılabilir türler için C# desen eşleştirme okunabilirliğini artırır.

Mantıksal Desenler (and, or, not)

Mantıksal desenler, and, or ve not anahtar kelimelerini kullanarak diğer desenleri birleştirerek tek bir desen içinde karmaşık koşullu kontrolleri mümkün kılar.

Öncesi:

public bool CanGrantAccessOld(UserRole role, int securityLevel, bool hasTwoFactorAuth)
{
    if ((role == UserRole.Administrator || role == UserRole.Manager) && securityLevel > 7 && hasTwoFactorAuth)
        return true;
    else if (role == UserRole.Developer && securityLevel > 5)
        return true;
    else if (role != UserRole.Guest && securityLevel >= 3 && securityLevel <= 10)
        return true;
    else
        return false;
}

public enum UserRole { Guest, User, Developer, Manager, Administrator }

Sonrası (Mantıksal Desenler kullanarak):

public bool CanGrantAccessNew(UserRole role, int securityLevel, bool hasTwoFactorAuth) => (role, securityLevel, hasTwoFactorAuth) switch
{
    (UserRole.Administrator or UserRole.Manager, > 7, true) => true,
    (UserRole.Developer, > 5, _) => true,
    (not UserRole.Guest, >= 3 and <= 10, _) => true,
    _ => false
};

Mantıksal operatörlerle birleştirilmiş C# is desen eşleştirmesi çok anlamlı hale gelir.

Var Deseni

var deseni bir ifadeyle her zaman eşleşir ve sonucunu yeni bir yerel değişkene atar. Özellikle bir switch ifadesinin (veya karmaşık bir desenin bir kısmının) tüm giriş değerini yakalamanız ve when yan tümcesi içinde ek, daha karmaşık kontroller yapmanız gerektiğinde, özellikle diğer desenler tarafından doğrudan ifade edilemeyen metot çağrıları veya özellikler içerenler için kullanışlıdır.

Öncesi:

using System.Collections.Generic;
using System.Linq;

public string AnalyzeNumberSequenceOld(IEnumerable<int> numbers)
{
    if (numbers == null)
        return "Invalid sequence (null)";
    if (numbers.Count() == 0)
        return "Empty sequence";
    if (numbers.Count() > 5 && numbers.Average() > 10.0)
        return "Long sequence with high average";
    return "Normal sequence";
}

Sonrası (when yan tümcesiyle Var Deseni kullanarak):

using System.Collections.Generic;
using System.Linq;

public string AnalyzeNumberSequenceNew(IEnumerable<int> numbers) => numbers switch
{
    null => "Invalid sequence (null)", 
    var list when list.Count() == 0 => "Empty sequence",
    var list when list.Count() > 5 && list.Average() > 10.0 => "Long sequence with high average",
    _ => "Normal sequence"
};

Burada, var list IEnumerable<int> örneğini yakalar. Bu, sonraki karmaşık LINQ sorgularının (Count() ve Average() gibi) when yan tümcesi içinde list değişkeni üzerinde doğrudan gerçekleştirilmesine olanak tanır, is kullanarak açık tür kontrollerine ihtiyaç duyulmaz.

Liste Desenleri (C# 11)

C# 11'de tanıtılan liste desenleri, bir dizideki (diziler veya List<T> gibi) öğelerle eşleştirmeye olanak tanır. Koleksiyonların yapısını ve içeriğini doğrulamak için inanılmaz derecede güçlüdürler.

Öncesi:

public bool ValidateLogEntryOld(string[] logParts)
{
    if (logParts == null || logParts.Length < 2) return false;

    if (logParts[0] == "ERROR" && logParts.Length >= 3 && logParts[1] == "AUTH" && logParts[2] == "FAILED")
        return true;
    if (logParts[0] == "INFO" && logParts.Length >= 2 && logParts[1] == "CONNECTED")
        return true;
    if (logParts[0] == "WARN" && logParts.Length >= 4 && logParts[1] == "DISK" && logParts[2] == "SPACE" && int.TryParse(logParts[3], out int space) && space < 10)
        return true;
    return false;
}

Sonrası (Liste Desenleri kullanarak):

public bool ValidateLogEntryNew(string[] logParts) => logParts switch
{
    ["ERROR", "AUTH", "FAILED", ..] => true, // Error authentication failed
    ["INFO", "CONNECTED", ..] => true,     // Client connected
    ["WARN", "DISK", "SPACE", var size, ..] when int.TryParse(size, out int space) && space < 10 => true, // Low disk space
    _ => false // Any other log entry
};

Bu, dizilere karşı desen eşleştirme için güçlü bir özelliktir, özellikle komut satırı argümanlarını veya farklı yapılara sahip günlük girdilerini ayrıştırma gibi senaryolarda kullanışlıdır. .. (dilim deseni) sıfır veya daha fazla öğeyi eşleştirerek esneklik sağlar.

Temel Bilgilerin Ötesinde: Desen Eşleştirme ile Daha Temiz Kod

Desen eşleştirmenin faydaları, salt sözdizimsel kolaylığın ötesine geçer. Bu özellikler benimsenerek, geliştiriciler doğal olarak şu şekilde kod yazarlar:

  • Daha Anlamlı: Desenler niyeti doğrudan aktarır, bu da kodu bir bakışta okumayı ve anlamayı kolaylaştırır. Karmaşık koşullu mantık sezgisel hale gelir.
  • Daha Özlü: Yinelemeli if-else bloklarını ve açık tür dönüştürmelerini ortadan kaldırmak kod hacmini azaltır, bu da daha az bakım gerektiren kod ve daha az hata olasılığına yol açar.
  • Daha Güvenli: Özellikle switch ifadeleri, genellikle kapsamlı desen eşleştirme gerektirir. C# derleyicisi, bir switch ifadesinin tüm olası giriş değerlerini kapsamaması durumunda geliştiricileri uyararak yardımcı olur ve çalışma zamanı istisnalarını önlemeye yardımcı olur. Derleyici tarafından zorunlu kılınan kapsamlılık, yazılımın doğruluğunu artırır.
  • Yeniden Düzenlemesi Daha Kolay: Daha temiz, daha modüler koşullu mantıkla, yeniden düzenleme daha az göz korkutucu hale gelir. Geliştiriciler, sistemin diğer kısımları üzerinde minimum etkiyle davranışı değiştirebilir veya genişletebilir.

Desen eşleştirme, C#'ı karmaşık veri işleme ve kontrol akışı için zarif çözümler sunan bir dile dönüştürdü. Temel tür kontrollerinden nesnelerin ayrıştırılmasına ve dizilerin doğrulanmasına kadar, C# 8.0 ve sonraki sürümlerinin sağladığı yetenekler, her modern yazılım geliştiricisi için temel araçlardır. Bu güçlü özellikleri benimsemek sadece kod kalitesini artırmakla kalmaz, aynı zamanda geliştirme sürecini de kolaylaştırır ve daha güvenilir ve sürdürülebilir uygulamalara katkıda bulunur. Hala eski tarz if-else veya switch ifadelerine güvenen geliştiriciler, bu desenleri dahil etmekten büyük ölçüde fayda sağlayabilir ve C# programlarını daha sağlam ve üzerinde çalışması daha keyifli hale getirebilirler.

İlgili makaleler