public interface IEnumerable { IEnumerator GetEnumerator(); }
Peki bu metodu kim çağıracakki biz implemente edelim?
foreach(var eleman in kolleksiyon)
foreach
Arka tarafta şunu yaratır:var oteleyen = kolleksiyon.GetEnumerator(); while(oteleyen.MoveNext()) // true dönerse, eleman var demektir { Console.WriteLine(oteleyen.Current); // eleman'ın ToString metodunu çağır ekrana yaz } oteleyen.Reset(); // kolleksiyonun içinde döndük sona geldik, başa dönmek için resetleyelim
Bu da güzeldi ancak biz sadece
GetEnumerator
metodunu anlayalım derken başımıza MoveNext()
, Current
ve Reset()
çıktı!!!Peki bize bu metotları sağlayan tip kimdir?
var oteleyen = kolleksiyon.GetEnuemerator(); // aslında şöyle de yazılabilir IEnumerator oteleyen = kolleksiyon.GetEnuemerator();Demekki tipimiz
IEnumerator
. Peki o zaman IEnumerator bize ne şartı koşuyor içine bakalım:public interface IEnumerator { object Current { get; } // Şimdi üstünde bulunduğum elemanı ver bakalım bool MoveNext(); // sonraki eleman mevcut mu? void Reset(); // en baştaki noktaya geri gidelim }
Anlaşıldıki bizim forEach bir IEnumerator(numaralandırıcı) istiyor ve onun nimetleri olan metot ve özelliği kullanarak kolleksiyon içinde dönüyor duruyor.
Peki bu tipin generic olması bize ne kazandırır? O zaman generic IEnumerator
public interface IEnumerator: IDisposable, IEnumerator { T Current { get; } // Sadece Current için T tipini sağlıyor. // Zaten Reset void döner, MoveNext ise bool geriye performans kaybı yaşatan Current kalıyor // Onuda T dönecek şekle getirirsek sorun giderilmiş olur. }
Peki GetEnumerator() metodu bize IEnumerator dönüyordu. Onu da generic ile IEnumerator
public interface IEnumerableŞimdi tip dönüşümlerinden kurtulduğumuza göre performans rahatlığıyla bu iki tipi kullanabiliriz.: IEnumerable { IEnumerator GetEnumerator(); }
Gelin kendimize bir örnek yazalım ve makalemizi sonlandıralım. Eğer anlaşılmayan yerler olursa lütfen yorumlarınızda sorun ;)
class Cem: IEnumerable , IEnumerator { T[] arr = new T[0]; int iCur = 0; int idx = -1; public T Current { get { return arr[idx]; } } object IEnumerator.Current { get { throw new NotImplementedException(); } } public void Add(T a) { Array.Resize(ref arr, arr.Length + 1); // dizimizi bir arttıralım ki yeni elemanı ekleyebilelim arr[arr.Length-1] = a; // artık bir büyüdüğüne göre -1 ile sonuncu sıraya yeni elemanı yerleştirelim } public void Dispose() { } public IEnumerator GetEnumerator() { return this; } public bool MoveNext() { var next = idx + 1; var sonuc = (next < arr.Length); if (sonuc) idx = next; return sonuc; } public void Reset() { idx = -1; } IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } } class Program { static void Main(string[] args) { var c = new Cem (); c.Add(22); c.Add(32); c.Add(42); c.Add(44); foreach (var a in c) Console.WriteLine(a); } }