C# programlama dili eğitim serimizde çok önemli bir kilometre taşına geldik. Bir önceki rehberimizde aynı tipteki verileri bir arada tutmak için Diziler (Arrays) kullanmayı öğrenmiştik. Ancak dizilerin çok büyük bir dezavantajı vardı: Boyutları sabittir. Yani 5 elemanlı bir dizi oluşturduğunuzda, sonradan 6. elemanı eklemek isterseniz programınız hata verir.
Peki ya bir e-ticaret sitesindeki alışveriş sepetini programlıyorsak? Kullanıcının sepete kaç ürün ekleyeceğini veya çıkaracağını önceden bilemeyiz. İşte bu gibi “boyutu sürekli değişebilen” dinamik durumlar için C# ve .NET SDK kütüphaneleri bize harika bir çözüm sunar: Koleksiyonlar (Collections).
Bu kapsamlı rehberde, C# koleksiyonlarının mantığını, en çok kullanılan koleksiyon tiplerini ve modern C# sürümleriyle gelen yepyeni koleksiyon özelliklerini örneklerle öğreneceğiz.
Koleksiyon (Collection) Nedir?
Koleksiyonlar, tıpkı diziler gibi verileri gruplamak ve saklamak için kullanılan, ancak dizilerden farklı olarak içine veri eklendikçe otomatik olarak büyüyen veya veri silindikçe otomatik olarak küçülebilen akıllı veri yapılarıdır.
C# dilinde foreach döngüleri, koleksiyonlar üzerinde gezinmeyi son derece basitleştirir ve arka planda indeks numaralarını sizin yerinize yöneterek hataları önler. C#, model tabanlı optimizasyonlar (pattern-based optimizations) sayesinde koleksiyonların oldukça basit ve yüksek performanslı bir şekilde işlenmesine olanak tanır.
En Sık Kullanılan C# Koleksiyon Tipleri
C# ekosisteminde birçok farklı koleksiyon tipi vardır ve her birinin kullanım amacı farklıdır. Yeni başlayan bir geliştirici olarak en sık karşılaşacağınız 4 temel koleksiyonu günlük hayattan örneklerle inceleyelim.
1. List (Dinamik Listeler)
List<T>, C# programcılarının en iyi dostudur ve günlük hayatta en çok kullanılan koleksiyon tipidir. Dizilerin esnek halidir. İstediğiniz kadar eleman ekleyebilir, aradan eleman silebilir veya listeyi sıralayabilirsiniz.
Günlük Hayat Örneği: Akıllı telefonunuzdaki “Yapılacaklar Listesi” (To-Do List) uygulaması. Gün içinde yeni görevler eklersiniz, bitenleri silersiniz; liste sürekli uzar veya kısalır.
// String (metin) tutan boş bir liste oluşturuyoruz
List<string> alisverisSepeti = new List<string>();
// Listeye yeni elemanlar ekleme
alisverisSepeti.Add("Dizüstü Bilgisayar");
alisverisSepeti.Add("Kablosuz Mouse");
alisverisSepeti.Add("Klavye");
// Listeden eleman çıkarma
alisverisSepeti.Remove("Klavye");
// Listedeki elemanları foreach ile ekrana yazdırma
Console.WriteLine("Sepetinizdeki Ürünler:");
foreach (string urun in alisverisSepeti)
{
Console.WriteLine($"- {urun}");
}
2. Dictionary<TKey, TValue> (Sözlükler / Anahtar-Değer Çiftleri)
Dictionary (Sözlük) koleksiyonu, verileri sadece alt alta sıralamak yerine, “Anahtar (Key)” ve “Değer (Value)” çiftleri olarak tutar. Bir sözlükte anahtarlar tamamen benzersiz (unique) olmalıdır.
Günlük Hayat Örneği: Telefon rehberiniz. Rehberde aynı isimden/numaradan tek bir kişinin kayıtlı olması esasına dayanır. Kişinin adı “Anahtar”, telefon numarası ise “Değer”dir. Adını aratarak numarasına anında ulaşırsınız.
// Anahtarı string (Plaka Kodu), Değeri string (Şehir Adı) olan bir sözlük
Dictionary<string, string> plakalar = new Dictionary<string, string>();
plakalar.Add("34", "İstanbul");
plakalar.Add("06", "Ankara");
plakalar.Add("35", "İzmir");
// Doğrudan anahtarı kullanarak değere çok hızlı erişim
Console.WriteLine($"34 plakalı şehrimiz: {plakalar["34"]}");
3. Queue (Kuyruk)
Queue koleksiyonu FIFO (First In First Out – İlk Giren İlk Çıkar) mantığıyla çalışır. Elemanlar kuyruğun sonuna eklenir ve her zaman kuyruğun en başındaki eleman ilk olarak işlenir.
Günlük Hayat Örneği: Bankadaki veya fırındaki müşteri kuyruğu. Sıraya ilk giren müşteri, hizmeti ilk alan kişidir. Yeni gelenler her zaman sıranın en arkasına geçer. E-ticaret sitelerinde siparişleri sırayla işlemek için arka planda bu yapı kullanılır.
Queue<string> musteriKuyrugu = new Queue<string>();
// Kuyruğa müşteri ekleme (Enqueue)
musteriKuyrugu.Enqueue("Ahmet");
musteriKuyrugu.Enqueue("Ayşe");
musteriKuyrugu.Enqueue("Mehmet");
// Kuyruktan müşteri alma ve çıkarma (Dequeue)
string siradakiMusteri = musteriKuyrugu.Dequeue();
Console.WriteLine($"İşlemi yapılan müşteri: {siradakiMusteri}"); // Ekrana Ahmet yazar
4. Stack (Yığın)
Stack koleksiyonu ise Queue’nun tam tersine LIFO (Last In First Out – Son Giren İlk Çıkar) mantığıyla çalışır. Elemanlar yığının en üstüne eklenir ve her zaman en üstteki (en son eklenen) eleman ilk önce alınır.
Günlük Hayat Örneği: Bulaşık yıkarken üst üste dizdiğiniz tabaklar. Yıkamak için her zaman en üstteki tabağı (yani yığına en son koyduğunuz tabağı) ilk alırsınız. Web tarayıcınızdaki “Geri (Back)” tuşu da tam olarak bu mantıkla çalışır; girdiğiniz son sayfaya sizi ilk olarak geri götürür.
Stack<string> webGecmisi = new Stack<string>();
// Yığına yeni web sayfası ekleme (Push)
webGecmisi.Push("Google.com");
webGecmisi.Push("Haberler.com");
webGecmisi.Push("WebSitem.com");
// Yığından en son eklenen sayfayı alma ve silme (Pop)
string sonSayfa = webGecmisi.Pop();
Console.WriteLine($"Geri dönülen sayfa: {sonSayfa}"); // Ekrana WebSitem.com yazar
Modern C# ile Koleksiyon İfadeleri (Collection Expressions)
C# dili sürekli gelişmektedir. Eski sürümlerde bir koleksiyonu başlatmak için uzun uzun new List<int> { 1, 2, 3 }; yazmamız gerekirdi. Ancak modern C# sürümleri ile birlikte Koleksiyon İfadeleri (Collection Expressions) adı verilen harika bir özellik gelmiştir.
Artık koleksiyon değerlerini sağlamak için köşeli parantezler [ ve ] kullanabilirsiniz. Derleyici (compiler), bu ifadeyi otomatik olarak gerekli koleksiyon tipine dönüştürür. Hatta .. (spread / yayma) operatörünü kullanarak farklı koleksiyonları tek bir koleksiyon içinde kolayca birleştirebilirsiniz.
// Modern C# Koleksiyon İfadesi ile kısa ve temiz yazım
int[] dizi1 =;
int[] dizi2 =;
// '..' (Spread) elemanı ile iki koleksiyonu genişletip birleştiriyoruz
List<int> birlesikListe = [..dizi1, ..dizi2, 7, 8];
// Sonuç: 1, 2, 3, 4, 5, 6, 7, 8
İndeks ve Aralık Seçimi (Index and Range Expressions)
İndekslenebilir bir koleksiyondan (Örn: List veya Array) belirli elemanları almak için İndeks (Index) ve Aralık (Range) ifadelerini kullanabiliriz.
^(şapka) işareti sondan anlamına gelir. Örneğin^1ifadesi, koleksiyonun en sonundaki elemanı temsil eder...ifadesi ise belirli bir aralığı ifade eder. Aralık, ilk indeksten başlar ve son indekse kadar (son indeks dahil olmadan) devam eder.
string[] kelimeler = ["C#", "öğrenmek", "çok", "eğlenceli", "bir", "süreçtir"];
// Sondan birinci kelimeyi alma (^1)
string sonKelime = kelimeler[^1]; // "süreçtir"
// Aralık (Range) alma (1. indeksten başla 4. indekse kadar)
string[] altKume = kelimeler[1..4]; // "öğrenmek", "çok", "eğlenceli"
Performans İpucu: Ne Zaman Koleksiyon, Ne Zaman Span?
Koleksiyonlar harikadır ancak bellekte (RAM) bir nesne olarak tahsis edilirler. Eğer uygulamanızda performansın çok kritik olduğu, işlemciyi çok yoran (CPU-bound) ve binlerce kez tekrar eden işlemler yapıyorsanız bellek yönetimini optimize etmeniz gerekir.
C# ve .NET mimarisinde, yüksek performanslı senaryolarda standart koleksiyonlar yerine belleğin ardışık bir bölümünü çok daha hızlı temsil edebilen Span<T> yapısının kullanılması tavsiye edilir. Span<T>, bellekte gereksiz kopyalamaların ve tahsislerin önüne geçerek uygulamanızı hızlandırır.
Sonuç
C# dilinde Koleksiyonlar, yazılım geliştiricilerin alet çantasındaki en önemli araçlardan biridir. Sabit boyutlu dizilerin aksine, uygulamalarımız büyüdükçe bizimle birlikte büyüyen, esnek ve akıllı yapılar kurmamızı sağlarlar. List ile dinamik verileri saklayabilir, Dictionary ile anahtar-değer eşleşmeleri yapabilir, Queue ve Stack ile verilerin işlenme sırasını profesyonelce yönetebilirsiniz. Bir sonraki durağımızda, bu verileri sihirli bir şekilde filtrelememizi ve sorgulamamızı sağlayan LINQ konusuna geçiş yapacağız!




