02 Temmuz 2025
Bu makalede, C# 11 ve 12'de tanıtılan ve kodunuzu basitleştirip geliştirme sürecini daha akıcı hale getiren bazı yeni özelliklere göz atacağız. Bu güncellemeler devrim niteliğinde olmayabilir, ancak pratik ve gereksiz karmaşıklığı azaltarak zaman tasarrufu sağlamak için tasarlanmıştır. Günlük kodlama görevlerinde küçük değişikliklerin nasıl daha temiz ve verimli çözümlere yol açabileceğini göreceğiz.
C#'ta karmaşık içerikli dizeler oluşturmak tarihsel olarak bir zorluk teşkil etmiştir. Geliştiriciler sıklıkla özel karakterleri, yeni satırları ve tırnak işaretlerini kaçırmak zorunda kalır, bu da uzun ve genellikle okunması zor kodlara yol açar. Bu süreç, özellikle JSON, XML veya düzenli ifadeler gibi formatlar doğrudan kaynak dosyalara gömüldüğünde zahmetli hale gelir.
C# 11, bu sorunu doğrudan ele almak için ham dize değişmezlerini tanıttı. Bu özellik, dizelerin birden fazla satıra yayılmasını ve kaçış dizilerine ihtiyaç duymadan gömülü tırnaklar ve ters eğik çizgiler dahil olmak üzere neredeyse her karakteri içermesini sağlar. Bir ham dize değişmezi, en az üç çift tırnak karakteriyle ("""
) başlar ve biter.
C# 11 Öncesi:
string oldJson = "{\r\n \"name\": \"Alice\",\r\n \"age\": 30\r\n}";
Console.WriteLine(oldJson);
C# 11 ile:
string newJson = """
{
"name": "Alice",
"age": 30
}
""";
Console.WriteLine(newJson);
Kapanış tırnaklarından önceki herhangi bir boşluk, dizenin minimum girintisini tanımlar ve derleyici bunu nihai çıktıda kaldırır. Ham dize değişmezleri, dizelerin okunabilirliğini büyük ölçüde artırır ve sözdizimi hatalarının olasılığını azaltır.
C#'ta desen eşleştirme önemli ölçüde gelişti ve C# 11, diziler veya listeler içinde sıra eşleştirme sağlamak için liste desenlerini tanıttı. Bu geliştirme, geliştiricilerin koleksiyon yapısını ve içeriğini kısa ve anlamlı bir şekilde incelemesine olanak tanır.
Daha önce, koleksiyon yapısını doğrulamak için uzunluk ve bireysel indeksler üzerinde manuel kontroller yapılması gerekiyordu, bu da uzun ve daha az sürdürülebilir kodlara yol açıyordu. Liste desenleri, sabit, tür, özellik ve ilişkisel desenler gibi alt desenleri destekleyerek bu sorunu çözer. Önemli özellikler arasında herhangi bir tek öğeyi eşleştirmek için atma deseni (_
) ve sıfır veya daha fazla öğeden oluşan bir diziyi eşleştirmek için aralık deseni (..
) bulunur.
C# 11 Öncesi:
int[] numbers = { 1, 2, 3 };
if (numbers != null && numbers.Length == 3 &&
numbers[0] == 1 && numbers[1] == 2 && numbers[2] == 3)
{
Console.WriteLine("Dizi tam olarak 1, 2, 3 içeriyor.");
}
if (numbers != null && numbers.Length >= 2 && numbers[1] == 2)
{
Console.WriteLine("Dizinin ikinci elemanı 2'dir.");
}
C# 11 ile:
int[] numbers = { 1, 2, 3 };
if (numbers is [1, 2, 3])
{
Console.WriteLine("Dizi tam olarak 1, 2, 3 içeriyor.");
}
if (numbers is [_, 2, ..])
{
Console.WriteLine("Dizinin ikinci elemanı 2'dir.");
}
Liste desenleri, sıra doğrulamasını kompakt ve okunabilir bir forma indirgeyerek bu tür işlemler için gereken kod satırlarını önemli ölçüde azaltır.
Nesne başlatma bazen, temel özelliklerin veya alanların atanmamış kaldığı istenmeyen bir duruma yol açabilir. Geleneksel olarak, geliştiriciler zorunlu başlatmayı tüm gerekli parametreleri kabul eden yapıcılar yoluyla veya yöntemler içinde savunma kontrolleri ekleyerek uygular.
C# 11, özellikler ve alanlar için derleme zamanı uygulama mekanizması olan required
değiştiricisini tanıttı. Bir üye required
olarak işaretlendiğinde, derleyici, nesne oluşturma sırasında bir değer almasını sağlar; bu, bir yapıcı veya nesne başlatıcı aracılığıyla olabilir. Bu, bir türün örneklerinin her zaman geçerli ve tamamen başlatılmış bir durumda olmasını garanti eder, eksik veriyle ilgili yaygın hataları önler.
C# 11 Öncesi:
public class OldPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public void DisplayName() => Console.WriteLine($"İsim: {FirstName} {LastName}");
}
// Kullanım:
var person = new OldPerson(); // Derleme zamanı hatası yok, ancak potansiyel olarak geçersiz nesne oluşturuluyor
person.DisplayName();
C# 11 ile:
public class NewPerson
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
public void DisplayName() => Console.WriteLine($"İsim: {FirstName} {LastName}");
}
// Kullanım:
// var person = new NewPerson(); // Derleme hatası - gerekli özellikler eksik
// var person = new NewPerson { FirstName = "John" }; // Derleme hatası - LastName eksik
var person = new NewPerson { FirstName = "Jane", LastName = "Doe" }; // Tamam
person.DisplayName();
Zorunlu üyeler, derleme zamanında başlatmayı zorunlu kılarak çalışma zamanı sürprizlerini ortadan kaldırır ve manuel kontroller ihtiyacını azaltır. Bu özellik, daha az savunma kodlaması ile kod güvenilirliğini artırır ve geliştiricilerin doğrulama yerine işlevselliğe odaklanmasını sağlar.
C# 12, daha önce yalnızca kayıt türlerine özgü olan bir özelliği genişleterek tüm sınıflar ve yapılar için birincil yapıcıları tanıttı. Bu, yapıcı parametrelerinin doğrudan tür tanımında bildirilmesini sağlar ve bunları tüm sınıf boyunca alanlar veya özellikler olarak otomatik olarak kapsamlandırır. Geleneksel yapıcıların aksine, bu yaklaşım açık alan bildirimlerini ve manuel atamaları atlar.
Burada çözülen temel sorun, nesne başlatmada tekrarlayan şablon kodlardır. Daha önce, geliştiriciler özel alanlar tanımlamak ve yapıcı argümanlarını açıkça bunlara eşlemek zorundaydı, bu da kod boyutunu gereksiz yere şişiriyordu. Birincil yapıcılar, başlatma mantığını doğrudan tür imzasına gömerek bunu basitleştirir.
C# 12 Öncesi:
public class OldProduct
{
private readonly int _productId;
private readonly string _productName;
public OldProduct(int productId, string productName)
{
_productId = productId;
_productName = productName;
}
public string PrintDetails() => $"Ürün ID: {_productId}, İsim: {_productName}";
}
// Kullanım:
OldProduct oldProd = new OldProduct(101, "Dizüstü Bilgisayar");
oldProd.PrintDetails();
C# 12 ile:
public class NewProduct(int productId, string productName)
{
public string PrintDetails() => $"Ürün ID: {productId}, İsim: {productName}";
}
// Kullanım:
NewProduct newProd = new NewProduct(102, "Klavye");
newProd.PrintDetails();
Birincil yapıcılar, veri merkezli türlerin tanımını inanılmaz derecede kısa hale getirir. Temel yapım parametrelerini doğrudan tür adının yanına yerleştirerek okunabilirliği artırır ve sınıfın veya yapının bağımlılıklarını bir bakışta netleştirir.
C#'ta koleksiyonları başlatmak tarihsel olarak koleksiyon türüne bağlı olarak farklı sözdizimlerini içeriyordu; örneğin, listeler için new List<T> { ... }
veya diziler için new T[] { ... }
. Mevcut koleksiyonları birleştirip yeni bir koleksiyon oluşturmak genellikle yinelemeli döngüler veya Concat()
gibi LINQ yöntemleri gerektiriyordu, bu da ek yük ve uzunluk ekliyordu.
C# 12, çok çeşitli koleksiyon türlerini oluşturmak ve başlatmak için birleşik ve kısa bir sözdizimi olan koleksiyon ifadelerini tanıttı. Basit bir [...]
sözdizimi kullanarak geliştiriciler diziler, listeler, Span<T>
ve diğer koleksiyon benzeri türler oluşturabilir. Yeni yayma elemanı (..
), mevcut koleksiyonlardan öğeleri doğrudan yeni bir koleksiyon ifadesine eklemeye olanak tanır ve manuel birleştirme ihtiyacını ortadan kaldırır.
C# 12 Öncesi:
// Farklı koleksiyonları başlatma
int[] initialNumbers = new int[] { 1, 2, 3 };
List<int> moreNumbers = new List<int> { 4, 5 };
// Koleksiyonları birleştirme
List<int> allNumbers = new List<int>();
allNumbers.AddRange(initialNumbers);
allNumbers.AddRange(moreNumbers);
allNumbers.Add(6);
allNumbers.Add(7);
Console.WriteLine(string.Join(", ", allNumbers));
C# 12 ile:
// Farklı koleksiyonları başlatma
int[] initialNumbers = [1, 2, 3];
List<int> moreNumbers = [4, 5];
// Yayma operatörü kullanarak koleksiyonları birleştirme
List<int> allNumbers = [..initialNumbers, ..moreNumbers, 6, 7];
Console.WriteLine(string.Join(", ", allNumbers));
Koleksiyon ifadeleri, koleksiyonları başlatma ve birleştirme uzunluğunu azaltarak daha temiz ve sezgisel bir sözdizimi sunar. Bu verimlilik, kodlamayı hızlandırır ve okunabilirliği artırır, daha az satırla daha büyük etki elde etme ilkesini destekler.
C#'ta fonksiyonel programlamanın temel taşlarından biri olan lambda ifadeleri, tarihsel olarak parametreleri için varsayılan değerler tanımlama yeteneğinden yoksundu. Bir lambda isteğe bağlı argümanları işlemek veya yedek değerler sağlamak gerekiyorsa, geliştiriciler lambda gövdesi içinde koşullu mantık kullanmak veya birden fazla aşırı yük tanımlamak zorunda kalıyordu, ancak lambda'lar doğrudan aşırı yükleri desteklemez.
C# 12, lambda ifadelerinde parametreler için varsayılan değerlere izin vererek bu boşluğu kapatır. Sözdizimi ve davranış, yöntem veya yerel işlev parametrelerini yansıtır ve esnek lambda işlevlerini tanımlamak için daha akıcı ve kısa bir yol sağlar.
C# 12 Öncesi:
// Varsayılan parametreler olmadan lambda.
// 'y' için bir varsayılan isteniyorsa, genellikle bir sarmalayıcı veya koşullu mantık gerekirdi:
Func<int, int, int> addOld = (x, y) => x + y;
Func<int, int> addWithDefaultOld = x => addOld(x, 10); // Yaygın bir geçici çözüm
Console.WriteLine(addOld(5, 3));
Console.WriteLine(addWithDefaultOld(5));
C# 12 ile:
// Varsayılan parametrelerle lambda
Func<int, int, int> addNew = (x, y = 10) => x + y;
Console.WriteLine(addNew(5, 3)); // y, 3'tür
Console.WriteLine(addNew(5)); // y varsayılan olarak 10 olur
Lambda'lar için varsayılan parametrelerin tanıtılması, esnekliklerini ve ifade gücünü önemli ölçüde artırır. Gereksiz lambda tanımları veya iç koşullu mantık ihtiyacını azaltır.
C# 11 ve 12, “Daha Az Yaz, Daha Çok Yap” vaadini yerine getiren etkileyici bir özellik seti sunar. C# 11'in ham dize değişmezleri ve liste desenlerinden C# 12'nin birincil yapıcılarına ve koleksiyon ifadelerine kadar bu gelişmeler, günlük kodlamadaki gerçek hayal kırıklıklarını ele alır. Gereksiz sözdizimini ortadan kaldırır, okunabilirliği yükseltir ve daha güvenli desenleri zorunlu kılarak yazılım geliştirme ve kod dönüştürme projelerindeki iş akışlarını doğrudan iyileştirir. Gerekli üyeleri zorunlu kılmak veya koleksiyon kurulumlarını basitleştirmek gibi her yenilik, tuş vuruşlarını azaltırken netliği artırır ve hata risklerini en aza indirir.