Published on

C# IEnumerator Nedir ? Foreach ve IEnumerable ile İlişkisi(C# Temel Arayüzleri 2)

Authors
  • avatar
    Name
    Alperen Önal
    Twitter

Bir önceki yazımızda IEnumerable'ı incelemiştik. Bu yazımızda da IEnumerator'u inceleyeceğiz. Ancak IEnumerator ve IEnumerable bağlantılı konu olduğu için tekrardan IEnumerable'ı tekrar edeceğiz.

IEnumerator, C#'da koleksiyonlar üzerinde iterasyon yapılmasını sağlayan bir arayüzdür.

IEnumerator, IEnumerable'ın "GetEnumerator" metodundan döndürülerek koleksiyon üzerinde iterasyon sağlanır.(IEnumerable'a gerek olmadan da iterasyon sağlanabilir. Ancak "IEnumerable"ın kullanılma sebebi kapsüllemeyi sağlamaktır.)


IEnumerator 3 ana üyeye sahiptir :

  1. MoveNext(), iteratör'ü koleksiyonun bir sonraki öğesine yönlendirir eğer bir öğe mevcutsa "true", mevcut değilse "false" döndürür.

  2. Current, koleksiyondaki geçerli öğeyi döner.

  3. Reset(), iteratör'ü koleksiyonun başına döndürür.

Öncelikle IEnumerable'ı tekrar edelim :

Aşağıdaki gibi class'larım olsun.

public class Ogrenci
{
    public string? Ad { get; set; }
    public string? Soyisim { get; set; }

    public int OgrenciID { get; set; }

    public Ogrenci(string ad, string soyad, int ogrenciID)
    {
        Ad = ad;
        Soyisim = soyad;
        OgrenciID = ogrenciID;



    }
}


public class Sinif
{
    public List<Ogrenci> ogrenciler;

    public Sinif()
    {
        ogrenciler = new List<Ogrenci>();
    }
    public void OgrenciEkle(Ogrenci ogrenci)
    {
        ogrenciler.Add(ogrenci);

    }

}

Ben, bu üstteki "Sinif" class'ı içerisinde iterasyon yaparak öğrencilerin isimlerini yazdırmak istiyorum diyelim.

Foreach kullandığım zaman hata alacağız çünkü "Sinif" class'ı herhangi bir GetEnumerator metodu kullanıp geriye IEnumerator döndürmüyor.

Örneğin :

namespace ornek
{
    public class Program
    {

        public static void Main(string[] args)
        {
            Sinif sinif = new Sinif();
            sinif.OgrenciEkle(new Ogrenci("Alperen", "Önal", 155));
            sinif.OgrenciEkle(new Ogrenci("Ahmet", "Çevik", 125));
            sinif.OgrenciEkle(new Ogrenci("Mehmet", "Kaya", 115));
            sinif.OgrenciEkle(new Ogrenci("Cemil", "Ay", 165));
            foreach (Ogrenci ogrenci in sinif) //burada hata alacağız
            {


            }

        }
    }

    public class Ogrenci
    {
        public string? Ad { get; set; }
        public string? Soyisim { get; set; }

        public int OgrenciID { get; set; }

        public Ogrenci(string ad, string soyad, int ogrenciID)
        {
            Ad = ad;
            Soyisim = soyad;
            OgrenciID = ogrenciID;



        }
    }

    public class Sinif
    {
        public List<Ogrenci> ogrenciler;

        public Sinif()
        {
            ogrenciler = new List<Ogrenci>();
        }
        public void OgrenciEkle(Ogrenci ogrenci)
        {
            ogrenciler.Add(ogrenci);

        }
    }
}

Peki bu hatayı nasıl çözebiliriz ? Evet, umarım sizin de aklınıza gelmiştir.

Kullandığımız koleksiyonun IEnumerator'ünü foreach içerisine döndürmeliyiz.

 public class Program
 {
     public static void Main(string[] args)
     {
         Sinif sinif = new Sinif();
         sinif.OgrenciEkle(new Ogrenci("Alperen", "Önal", 155));
         sinif.OgrenciEkle(new Ogrenci("Ahmet", "Çevik", 125));
         sinif.OgrenciEkle(new Ogrenci("Mehmet", "Kaya", 115));
         sinif.OgrenciEkle(new Ogrenci("Cemil", "Ay", 165));
         foreach (Ogrenci ogrenci in sinif.ogrenciler)
         {
             Console.WriteLine(ogrenci.Ad);

         }

     }
 }

Veya alttaki gibi de kullanabilirsiniz .)

 public class Program
    {

        public static void Main(string[] args)
        {
            Sinif sinif = new Sinif();
            sinif.OgrenciEkle(new Ogrenci("Alperen", "Önal", 155));
            sinif.OgrenciEkle(new Ogrenci("Ahmet", "Çevik", 125));
            sinif.OgrenciEkle(new Ogrenci("Mehmet", "Kaya", 115));
            sinif.OgrenciEkle(new Ogrenci("Cemil", "Ay", 165));
            foreach (Ogrenci ogrenci in (IEnumerable)sinif.ogrenciler)
            {
                Console.WriteLine(ogrenci.Ad);

            }

        }
    }

"sinif.ogrenciler", olarak kullandığımızda foreach'a kullandığımız List'in IEnumerator'ünü sunuyor ve iterasyon yapabiliyoruz.

Evet, yukarıdaki kodlarda sorun çözülmüş gibi gözüküyor ancak bu OOP'nin "encapsulation" ilkesini bozuyor. Kullandığımız koleksiyonu doğrudan dışarı açıyoruz.

Bu şekilde olmamalı. Bunun yerine IEnumerable ekleyerek kapsülleme yapmalıyız.

Örneğin :

namespace ornek
{
    public class Program
    {

        public static void Main(string[] args)
        {
            Sinif sinif = new Sinif();
            sinif.OgrenciEkle(new Ogrenci("Alperen", "Önal", 155));
            sinif.OgrenciEkle(new Ogrenci("Ahmet", "Çevik", 125));
            sinif.OgrenciEkle(new Ogrenci("Mehmet", "Kaya", 115));
            sinif.OgrenciEkle(new Ogrenci("Cemil", "Ay", 165));
            foreach (Ogrenci ogrenci in sinif)
            {
                Console.WriteLine(ogrenci.Ad);

            }

        }
    }

    public class Ogrenci
    {
        public string? Ad { get; set; }
        public string? Soyisim { get; set; }

        public int OgrenciID { get; set; }

        public Ogrenci(string ad, string soyad, int ogrenciID)
        {
            Ad = ad;
            Soyisim = soyad;
            OgrenciID = ogrenciID;



        }
    }


    public class Sinif:IEnumerable
    {
        private List<Ogrenci> ogrenciler;

        public Sinif()
        {
            ogrenciler = new List<Ogrenci>();
        }

        public void OgrenciEkle(Ogrenci ogrenci)
        {
            ogrenciler.Add(ogrenci);

        }
        public IEnumerator GetEnumerator()
        {
            return ogrenciler.GetEnumerator();
        }


    }

}

IEnumerator Kullanımı

Aşağıdaki kodumuzda "SinifEnumerator" isimli Enumerator class'ı oluşturduk ve Sinif->GetEnumerator()'ü buraya bağladık.


namespace ornek
{
    public class Program
    {

        public static void Main(string[] args)
        {
            Sinif sinif = new Sinif();
            sinif.OgrenciEkle(new Ogrenci("Alperen", "Önal", 155));
            sinif.OgrenciEkle(new Ogrenci("Ahmet", "Çevik", 125));
            sinif.OgrenciEkle(new Ogrenci("Mehmet", "Kaya", 115));
            sinif.OgrenciEkle(new Ogrenci("Cemil", "Ay", 165));
            foreach (Ogrenci ogrenci in sinif)
            {
                Console.WriteLine(ogrenci.Ad);

            }

        }
    }

    public class Ogrenci
    {
        public string? Ad { get; set; }
        public string? Soyisim { get; set; }

        public int OgrenciID { get; set; }

        public Ogrenci(string ad, string soyad, int ogrenciID)
        {
            Ad = ad;
            Soyisim = soyad;
            OgrenciID = ogrenciID;



        }
    }


    public class Sinif:IEnumerable
    {
        private List<Ogrenci> ogrenciler;

        public Sinif()
        {
            ogrenciler = new List<Ogrenci>();
        }

        public void OgrenciEkle(Ogrenci ogrenci)
        {
            ogrenciler.Add(ogrenci);

        }
        public IEnumerator GetEnumerator()
        {
            return new SinifEnumerator(ref this.ogrenciler);
        }


    }

    public class SinifEnumerator : IEnumerator
    {
        private readonly List<Ogrenci> _ogrenciler;
        private int index = -1;
        public SinifEnumerator(ref List<Ogrenci> ogrenciler)
        {
            _ogrenciler = ogrenciler;

        }
        public object Current { get { return _ogrenciler[index]; } }

        public bool MoveNext()
        {
            index++;
            return index >= _ogrenciler.Count ? false : true;
        }

        public void Reset()
        {
            index = -1;
        }
    }




}


Şimdi bu yapıyı atomik olarak inceleyelim.

IEnumerator 3 ana üyeye sahiptir demiştik. Bunlar :

  1. MoveNext()

index'i 1 arttırdık ve bulunduğumuz index'de bir öğe var mı yok mu diye kontrol sağladık.

  1. Current

Bulunduğumuz index'deki öğeyi döndürdük.

  1. Reset()

index'e "-1" atadık.

IEnumerator'ün indexi, -1 olarak belirledik çünkü koleksiyon üzerinde çalışmaya başladığımız gibi index'i 1 arttırarak ele aldık.(index'e farklı atamalar yapabilirsiniz ama "-1" atanarak ele alınması tercih ediliyor. Çünkü .NET tarafından da bu şekilde yazılmış. Biz de onları örnek aldık.)

Resim üzeriden gösterecek olursak :


Bu yazımız bu kadardı serinin kalan yazılarında görüşmek üzere.

Kaynakça : codeguru.com/csharp/ienumerable-ienumerator-c-sharp/