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); } } 
 
