C# 8.0 – Ranges and Indices
Merhaba,
Yazılım dillerinde koleksiyonlar veya diziler üzerinde işlem yaparken ilgili yapıyı sadeleştirmek yahut verisel açıdan manüpüle edebilmek için LINQ sorgularından ya da her türlü tarafımızca veya harici geliştirilmiş algoritmalardan faydalanırız. C#, 8.0 versiyonunda koleksiyonel veri kaynakları üzerinde gerekli manipülasyonu sağlayabilmek ve bunun yanında kaynak içerisindeki tüm veriler üzerinde yapılan genel sorgulamalar ve algoritmalardan kaçınmak, yani direkt olarak hedef veri/ler odaklı çalışabilmek için yeni tipler ile operatörler geliştirmiş bulunmaktadır.
C# 8.0 ile gelen yeni tiplerimiz System.Index ile System.Range structerları iken, yeni işlevsel operatörlerimiz ise .. ile ^ ifadeleridir.
Şimdi gelin öncelikle yeni üretilen tipleri ele alarak ardından sırasıyla operatörleri inceleyelim.
System.Index
Dizi ve koleksiyon yapılarındaki index kavramının static tip olarak belirlenmiş halidir. Temelde index değerini tutmakla beraber ^ operatörüyle birlikte daha fazla bir anlam ifade etmekte ve dizinin index değerlerini tersine ifade edecek şekilde bir sorumluluk yüklenmektedir.
Şöyle ki;

Yukarıdaki ekran görüntüsünde görüldüğü üzere “Index” structer tipinde tanımlanan “index” isimli “3” değerine sahip değişken “isimler” referansına sahip string dizisinin 3. index değerine tekabül etmektedir. Evet… Bu zaten bildiğimiz bir durumdur. Aşağıdaki görselde göz gezdirerek bir üstteki paragrafta bahsedilen ^ operatörü ile nasıl bir çalışma mantığında olduğunuda inceleyelim.
Görüldüğü üzere index olarak tutulan sayısal değer ^ operatörü ile tersine bir index olarak tanımlanmıştır. Dolayısıyla bu şekilde tanımlanan bir ifade herhangi bir dizi yahut koleksiyonel bir değerde tersine indexe denk gelen datayı bizlere getirecektir. Burada dikkat edilmesi gereken nokta şudur ki; tersine index durumlarında index değerleri 0’dan değil 1’den başlamasıdır.
“Index” tipinin buradaki en büyük avantajı, tersine index durumunun sayısal olarak elimizde ifade edilmesini sağlamasıdır. Normal şartlarda herhangi bir sayısal değişkende bu değeri ifade etmemiz mümkün değildir.
![]()
Index tipinin kullanımına dair aşağıdaki örneği inceleyebilirsiniz.
string[] isimler = { "Hüseyin", "Hilmi", "Rıfkı", "Hatice", "Ayşe", "Mahmut", "Kazım", "Okan", "Emre", "Ali", "Naci", "Hüsnü", "Kamil" };
Index i1 = ^3;
Index i2 = 4;
Console.WriteLine($"{isimler[i1]} - {isimler[i2]}");
System.Range
Koleksiyonel veri üzerinde hangi değerler ile çalışacağımızı belirleyebilmek için index üzerinden aralık vermemizi ve bu bağıntıyı .. operatörü ile gerçekleştirmemizi sağlayan yapılanmanın kendine özgü türü Range yapısıdır.
Yukarıdaki görseli incelerseniz eğer Range değişkeninin tuttuğu aralığın solundaki değer index bazlı bir göstergeye sahipken, sağındaki ise sıra numarasını ifade etmektedir. Dolayısıyla bu iki değerlere denk gelen verilerde dahil olmak üzere aralarındaki tüm veriler ilgili koleksiyonel değerde elde edilecektir. Örnek olarak görselin sonucu baz alınırsa; “Hatice”, “Ayşe”, “Mahmut” ve “Kazım” değerleri elde edilecektir.

Yine bir üstteki görselde elde edilen sonucu tekrar elde edebilmek için yukarıdaki gibi bir çalışma gerçekleştirebiliriz. Burada dikkat edilmesi gereken nokta, .. operatörünün sağında ya da solunda ^ operatörü kullanılıyorsa sıra numarasına denk gelen ilgili değerin koleksiyona dahil olmadığıdır.

Örneğin yukarıdaki görseldeki çalışmada; “Okan”, “Emre” ve “Ali” değerleri elde edilecektir.
Range tipine özel aşağıdaki örneği inceleyiniz;
string[] isimler = { "Hüseyin", "Hilmi", "Rıfkı", "Hatice", "Ayşe", "Mahmut", "Kazım", "Okan", "Emre", "Ali", "Naci", "Hüsnü", "Kamil" };
Range range = ^6..10;
foreach (var item in isimler[range])
{
Console.WriteLine(item);
}
Buda bir ikinci örnek;
string[] isimler = { "Hüseyin", "Hilmi", "Rıfkı", "Hatice", "Ayşe", "Mahmut", "Kazım", "Okan", "Emre", "Ali", "Naci", "Hüsnü", "Kamil" };
Index i1 = 3;
Index i2 = ^7;
Range range = i1..i2;
foreach (var item in isimler[range])
{
Console.WriteLine(item);
}
Vee son örnek;
string[] isimler = { "Hüseyin", "Hilmi", "Rıfkı", "Hatice", "Ayşe", "Mahmut", "Kazım", "Okan", "Emre", "Ali", "Naci", "Hüsnü", "Kamil" };
var list = isimler.ToList().GetRange(3, 4); //Eski usul
var list2 = isimler.Skip(3).Take(4); //Eski usul
Index i1 = 3;
Index i2 = 7;
Range range = i1..i2; //Yeni usul
foreach (var item in isimler[range])
Console.WriteLine(item);
Console.WriteLine("************");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine("************");
foreach (var item in list2)
Console.WriteLine(item);
Indexer[ ] içerisine tam sayı verilebildiği gibi Range yahut Index türüde verilebilir.
.. Operatörü
Koleksiyonel verilerde belirli aralığı temsil eden operatördür. Aralık operatörü diyede isimlendirebiliriz. Genellikle indexer[ ] operatörü içerisinde indexsel aralığı belirlemek için kullanılır.

Yukarıdaki ekran alıntısında görüldüğü gibi sağına ve soluna sayısal bir değer alabildiği gibi özü itibariyle System.Index türünden de değerler alabilir ve geriye bir System.Range türünden yapı döndürür. Bu yapı kullanılarak ilgili değerlere karşılık gelen index aralıklarına giren tüm verilerin elde edilmesini sağlar.
Eskiden .. operatörü olmaksızın ihtiyaca dönük operasyonları hangi işlemlerle gerçekleştiriyorduk aradaki farkı görmek için aşağıdaki kod bloğunu inceleyiniz;
string[] isimler = { "Hüseyin", "Hilmi", "Rıfkı", "Hatice", "Ayşe", "Mahmut", "Kazım", "Okan", "Emre", "Ali", "Naci", "Hüsnü", "Kamil" };
var list = isimler.ToList().GetRange(3, 4); //Eski usul
var list2 = isimler.Skip(3).Take(4); //Eski usul
Index i1 = 3;
Index i2 = 7;
Range range = i1..i2; //Yeni usul
foreach (var item in isimler[range])
Console.WriteLine(item);
Console.WriteLine("************");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine("************");
foreach (var item in list2)
Console.WriteLine(item);
Yerine geldiği genel kullanım operasyonlarına bakınca genellikle veri sayfalama vb. işlemlerde oldukça kullanışlı bir işleve sahip olduğu aşikardır.
^ Operatörü
Koleksiyonel yapılarda index değerinin tersini ifade eder. Normal index yapılanmasına nazaran ters index durumu 0’dan değil, 1’den başlamaktadır. Yani 10 elemanlı bir dizide; sonuncu eleman 9. indexe sahiptir lakin tersine operatörüyle “^0” değil “^1” değerine tekabül etmektedir.

Görüldüğü üzere yanına yazılan ifade sayısal bir değer(tam sayı) olmak zorundadır. Sonuç olarak geriye bir System.Index türünden değer döndürür.
^ operatörü genellikle bir dizinin son elemanına erişmek için kullandığımız aşağıdaki karışık manevrasal algoritmadan bizleri kurtarmaktadır.
Eski stil;
string isim = isimler[isimler.Length - 1];
Yeni stil;
string isim = isimler[^1];
Son söz olarak;
Her yeni özellikte olduğu gibi bu özelliklerde biz yazılımcılar için daha kafiyeli kod yazmamıza olanak tanıyacaktır. Lakin tüm bu özellikler başlı başına bir anlam ifade ettiği için C# programlama dili okunabilirlik ve anlaşılabilirlik açısından oldukça zor bir hale bürünmektedir. Dili yeni öğrenenler daha temel mantıksal operatörleri oturtmakta zorlanırken, üsttüne üstlük temel yapıları ilgilendiren bu tarz yeni ve işlevsel açıdan ileri düzel operatörleri öğrenmeyi sonraki süreçlere(günlere/aylara ve hatta yıllara) bırakmalarını tavsiye ederim.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…






Güzel makale eline sağlık