C#’ta IEnumerable ve IEnumerator Interfaceleri Nedir? ve Nasıl Kullanılır?
Merhaba,
C#’ta koleksiyon yahut array yapıları üzerinde periyodik bir düzende dönmemizi ve verileri bu şekilde tek tek elde etmemizi sağlayan foreach döngüsünün temel çalışma prensibi olan iterasyon mantığının kendi sınıflarımız üzerinde nasıl uygulanacağını inceleyeceğiz. Biliyorsunuz ki C#’ta iterasyon dendiğinde akla ilk olarak foreach döngüsü gelmektedir. Yani, bir sınıfa iterasyon özelliği kazandırabilirsek foreach döngüsü bu sınıfla etkileşime girebilecek iterasyonun periyoduna göre ilgili sınıf içerisinde belirlenen işlemleri gerçekleştirecek. Bir sınıfa iterasyon özelliklerini kazandırmak için gereken tüm özellikler IEnumerator interface’i aracılığıyla elde edilebilmektedir. IEnumerable interface’i ise bir sınıfa foreach mekanizması tarafından tanınması için gerekli yetenekleri/nitelikleri kazandırır. Yani enumerator yapısını… Şimdi gelin bu iki interface yapısını detaylıca irdeleyerek, nasıl kullanıldıklarına değinelim.
Şimdi herşeyi en temelden ele alarak anlatmaya başlayalım.
Hani koleksiyonlarda kullandığımız “List” gibi, “Dictionary” gibi referanslardan üretilen nesneler direkt olarak foreach döngüsüne verilebilmektedir. Öyne değil mi?
static void Main(string[] args)
{
List<string> Isimler = new List<string>();
Isimler.Add("Gençay");
Isimler.Add("Nurgül");
Isimler.Add("Ayşe");
Isimler.Add("Fatih");
Isimler.Add("Ilgaz");
foreach (var isim in Isimler)
Console.WriteLine(isim);
Console.Read();
}
}
Bakın Isimler referansında bir List nesnesi oluşturdum ve bu nesneyi işaret eden referansı foreach döngüsünde verdiğim vakit sıkıntısız çalışmaktadır.
Eee… Peki örneğin “Personeller” isminde bir sınıf oluştursak. Bunu direkt olarak foreach döngüsüne verebiliyor muyuz?

Hayır… Neden?
Çünkü, yazmış olduğumuz sınıfımızı foreach döngüsünün istediği şartlarda yapılandırmadığımız için. foreach döngüsü bir sınıf üzerinde çalışacaksa o sınıfın kesinlikle ve kesinlikle içerisinde geriye IEnumerator döndüren GetEnumerator metodunun bulunmasını ister. Tek şartı budur.
Videodan da gördüğünüz gibi GetEnumerator metodu sınıf içerisine eklendiğinde foreach döngüsü ilgili sınıfın nesnesini kabul etmektedir.
Peki nedir bu GetEnumerator metodu?
GetEnumerator metodu, bir sınıfa iterasyon yapılarını kazandıracak özellikleri barındıran IEnumerator nesnesi dönen bir metotdur.
İşte o yüzden foreach bu metodu gördüğü anda ilgili sınıfın bir iterasyon mantığıyla çalıştığını düşünmekte ve kabul etmektedir. Velhasıl birazdan bu metodun detaylarına geleceğiz.
Şimdi kaldığımız yerden devam edelim.
Metodumuzun içerisine GetEnumerator metodunu ekledikten sonra direkt olarak foreach döngüsünde ilgili sınıfımızı çalıştıramayacağız. Bunun sebebi, sınıfımız içerisinde hangi veri topluluğu üzerinde işlem yapılacağının belirlenmiş olmamasıdır. Ayriyetten GetEnumerator metodu içerisinde de bir enumerator nesnesi dönmemiz gerekecektir.
O halde hemen eksikliklerimizi tamamlayalım…
class Personel
{
public int Id { get; set; }
public string Adi { get; set; }
public string SoyAdi { get; set; }
}
class Personeller
{
List<Personel> PersonelListesi = new List<Personel>();
public void Add(Personel p)
{
PersonelListesi.Add(p);
}
public IEnumerator GetEnumerator()
{
return PersonelListesi.GetEnumerator();
}
}
Örneğimizde bir “Personel” sınıfı oluşturup, “Personeller” sınıfı içerisinde ilgili sınıfın koleksiyon yapısını ve bu koleksiyona veri ekleme işlevini yapan Add metodunu tanımladım. GetEnumerator metodu içerisinde ise koleksiyonumuzun GetEnumerator() metodu sayesinde bir enumerator elde edip return ettim.
Diziler ve koleksiyonlar(collections) itere(itersayon) edilebilir yapılar oldukları için içlerinde GetEnumerator metodu bulunmaktadır.
Bu yazımızın ileri satırlarında IEnumerator interface’ini detaylandırırken, kendi enumeratorümüzü oluşturmayıda konuşacağız. Ama şimdilik bu örneğimizde koleksiyon yahut dizi yapılarının GetEnumerator metodunu kullanmamız işimizi yeterince görmektedir.
Velhasıl… Yaptığımız bu işlemler neticesinde “Personeller” sınıfımız, içerisinde bir “Personel” veri kümesi barındıran ve bu veri kümesi üzerinde itere edilebilir bir nitelik arz eden bir sınıf mahiyetindedir.
Şuana kadar yaptığımız çalışmayı derleyip foreach döngüsünde sınıfımızı test ettiğimiz vakit çalıştığını göreceğiz.
class Program
{
static void Main(string[] args)
{
Personeller personeller = new Personeller();
personeller.Add(new Personel { Id = 1, Adi = "Gençay", SoyAdi = "Yıldız" });
personeller.Add(new Personel { Id = 2, Adi = "Aslı", SoyAdi = "Cambaz" });
personeller.Add(new Personel { Id = 3, Adi = "Elif", SoyAdi = "Gök" });
personeller.Add(new Personel { Id = 4, Adi = "Aykız", SoyAdi = "Yıldız" });
personeller.Add(new Personel { Id = 5, Adi = "Erol", SoyAdi = "Burçak" });
foreach (Personel personel in personeller)
Console.WriteLine($"ID : {personel.Id}\nAdı : {personel.Adi}\nSoyadı : {personel.SoyAdi}\n*****");
Console.Read();
}
}
Burada dikkatinizi çekmek istediğim bir husus var. “Personeller” sınıfını foreach döngüsünde kullanırken döngü değişkeninin(personel) tipini “var” olarak belirleyip ilgili nesnenin tipini belirlemeyi compilera bırakabilirdik. Lakin şuana kadar yapmış olduğumuz tüm işlemler döngü değişkeninin object olarak gelmesini sağlamaktadır. O yüzden direkt olarak cast işlemi uygulatıyor, “var” yerine “Personel” tipini kullanıyorum.

Eğer ki siz “var” kullanmak istiyorsanız GetEnumerator metodunun geri dönüş tipini aşağıdaki gibi generic IEnumerator olarak tanımlamanız gerekmektedir.
...
public IEnumerator<Personel> GetEnumerator()
{
return PersonelListesi.GetEnumerator();
}
...

Bu ek bilgiden sonra artık konumuzun ikinci ana unsuruna gelebiliriz.
Evet sevgili okurlarım… Gördüğünüz gibi, oluşturmuş olduğumuz herhangi bir sınıfı itere edilebilir hale getirmeyi ve foreach döngüsü ile bu sınıf üzerinde dönmeyi görmüş olduk.
Şimdi makalemizin bu noktasına gelen okuyucularımın kafalarında muhakemesini yaptıkları konuşmalar sanırım üç aşağı beş yukarı aşağıda tahmin ettiğime benzer niteliktedir.
Ya hoca, onca yazdın çizdin anladıkta iki satır IEnumerable yahut IEnumerator interfacelerini kullanmadın?
Evet. Şu ana kadar hiç IEnumerable ve IEnumerator interfacelerini kullanmadım diyebiliriz. Haydi gelin şimdi bu interfaceleri tek tek ele alalım ve bu sırada yukarıdaki satırlarda bahsettiğimiz GetEnumerator metodunuda tam teferruatlı masaya yatıralım.
IEnumerable Interface’i
IEnumerable interface’i sayesinde bir sınıf itere edilebilir özellik kazanmaktadır. Peki bir sınıfın itere edilebilirlik özellik kazanması neydi? diye sorarsak eğer üst satırlarda bahsettiğimiz gibi o sınıfın geriye IEnumerator nesnesi dönen GetEnumerator isimli metodu barındırıyor olması demekti. Ee haliyle IEnumerable interface’i ilgili sınıfa uygulandığında GetEnumerator metodunu implement edecektir.
Yani uzun lafın kısası IEnumerable interface’in implement edildiği bir class üzerine GetEnumerator metodu uygulattırılır. Haliyle yukarıda yaptığımız gibi ilgili metodu manuel olarak yazmaktan ve olası imla hatalarından bizleri kurtarmaktadır.
class Personel
{
public int Id { get; set; }
public string Adi { get; set; }
public string SoyAdi { get; set; }
}
class Personeller : IEnumerable<Personel>
{
List<Personel> PersonelListesi = new List<Personel>();
public void Add(Personel p)
{
PersonelListesi.Add(p);
}
public IEnumerator<Personel> GetEnumerator()
{
return PersonelListesi.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return PersonelListesi.GetEnumerator();
}
}
Görüldüğü üzere çok rahat bir şekilde ilgili sınıfımız itere edilebilir hale getirilmektedir.
IEnumerator Interface’i
IEnumerable interface’i ile bir sınıf itere edilebilir hale getiriliyor, bu işlem içinde GetEnumerator metodu sınıfa implement ediliyordu. IEnumerator interface’i ise iterasyon özelliği kazandıracak ve iterasyon işleminde kullanılacak elemanları ve özellikleri barındırmaktadır.
Bu elemanlar/özellikler;
- Current
İterasyon’da kalınan yeri temsil eder. - MoveNext
İterasyon’da bir sonraki adım var mı?/yok mu? kontrolünü sağlar. - Reset
İterasyon’u başa alır. - Dispose
İterasyon’un bittiğini temsil eder.

Bu görsel http://www.yazilimgunlugu.com/ienumerable-ve-ienumerator-ara-yuzleri-ve-kullanimi-makalesi/738.aspx adresinden alınmıştır.
Biz şuana kadar ilgili sınıfımız içerisinde kullandığımız veri kümesinin GetEnumerator metodu aracılığıyla enumerator’umüzü elde ettik. Haydi gelin şimdi de kendi enumerator’umüzü yazalım.
class PersonelEnumerator : IEnumerator<Personel>
{
List<Personel> Kaynak;
int currentIndex = -1;
public PersonelEnumerator(List<Personel> Kaynak) => this.Kaynak = Kaynak;
public Personel Current => Kaynak[currentIndex];
object IEnumerator.Current => Kaynak[currentIndex];
public void Dispose() => Console.WriteLine("İterasyon bittiii...");
public bool MoveNext() => ++currentIndex < Kaynak.Count;
public void Reset() => currentIndex = 0;
}
Ve “Personeller” sınıfındaki GetEnumerator metodundan kendi yazdığımız enumerator nesnesini dönelim.
class Personel
{
public int Id { get; set; }
public string Adi { get; set; }
public string SoyAdi { get; set; }
}
class Personeller : IEnumerable<Personel>
{
List<Personel> PersonelListesi = new List<Personel>();
public void Add(Personel p) => PersonelListesi.Add(p);
public IEnumerator<Personel> GetEnumerator() => new PersonelEnumerator(PersonelListesi);
IEnumerator IEnumerable.GetEnumerator() => new PersonelEnumerator(PersonelListesi);
}
IEnumerable ve IEnumerator interfaceler’i ile sizlerde oluşturduğunuz sınıflara itere özellikleri kazandırabilir, hatta IEnumerator interface’i ile oluşturduğunuz enumerator’de isteğinize göre iterasyonun periyodunu ayarlayabilir ve foreach döngüsünde kullanabilirsiniz.
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…



Merhaba,
Bu konuyla ilgili bir sorum olacak. veritabanındaki il ve ilçeleri IEnumerable vs. arayüzü ile comboboxlara çekebilir miyiz ? İl seçince ile göre ilçeyi nasıl getiririz ? Bunu datatable ile yapabiliyorum ama Generic List ile yapayım dedim kafam iyice karıştı. Bunu yapabilen bir örnek yapabilir misin rica etsem ?
Teşekkür ederim.
Hocam rica etsem şu makalelerdeki ve sitenizdeki türkçe karakterlerin bold olması sorununu düzeltir misiniz. Gerçekten ona takılmaktan makalenizi okuyamıyorum acayip deli etti beni gerçekten 🙂
🙂 Bu meseleyi bir kişi daha dillendirmişti. Doğrusunu söylemek gerekirse Muhammed kardeşim şu günlerde bu meseleyle hiç uğraşamam 🙂 Bu site üzerine düşkünlüğümü bilirsiniz ki hemen hemen her konuda titiz davranmaktayım. Lakin bazen bu tarz ufak tefek sorunlara nazarı olsun diye göz yummaktayım.
Hocam sen söylemesen farketmemiştim algıda seçicilik oldu artık bende takılıyorum sağol 🙂
çok faydalı bir makale
Açıklayıcı bir yazı olmuş, elinize sağlık. Çok faydalandım 🙂
Gençay hocam,
her zamanki gibi farkındalık yaratma konusunda çok yetenekli olduğunuzu bir kez daha “fark etmiş” oldum. Emeklerinize sağlık.
Bir sınıf (class), foreach gibi koleksiyon boyunca yineleme seçenekleri sunan bir IEnumerator döndürmez.
Bu yüzden, “foreach döngüsü bir sınıf üzerinde çalışacaksa o sınıfın kesinlikle ve kesinlikle içerisinde geriye IEnumerator döndüren GetEnumerator metodunun bulunmasını ister.” (Gençay YILDIZ’dan alıntı)
Bu da Class ‘ın IEnumarable interface inden miras alması ile sağlanabilir.
class PersonelEnumerator : IEnumerator { ... public IEnumerator GetEnumerator() { return PersonelListesi.GetEnumerator(); } }Naçizane…
Çok alakasız bir şey aratırken buraya nasıl geldim bilmiyorum ama güzel makale eline sağlık 🙂
İyi bir blog yazısı
çok faydalı bir yazı olmuş teşekkürler
Cok faydali bilgiler, sagolun hocam
public void Reset() => currentIndex = 0; satırında değer -1 olmalı değil mi?