Geçtiğimiz günlerde, foreach iterasyonu ve yield operatörü ile ilgili detaylı bilgileri sizlerle paylaşmıştım. Kısaca hatırlamaya çalışalım. Kendi yazdığımız bir tip içerisinde foreach ile iterasyon yapılması için IEnumerable interface’ine ihtiyaç duymuştuk. Bu interface ile sınıfa GetEnumerator metodunu kazandırmıştık. GetEnumerator metodu da geriye IEnumerator interface’ini implement eden bir sınıf döndürmekteydi. Bu sınıfın da iterasyonu sağladığını görmüştük. Ancak, current property’si geriye object döndürdüğü için, iterasyon sonucunda elde ettiğimiz her nesneyi istediğimiz tipe cast etmemiz gerekmişti.

Makalemizin konusu da tam olarak bu noktada devreye giriyor. Çünkü burada tip güvenliği söz konusudur. Yazmış olduğumuz sınıf zaten Urun tipinden nesneler içerdiğinden dolayı, iterasyon sonucunda sadece Urun tipinden nesnelerin elde edilebilmesini sağlamaya çalışacağız. Bunu da IEnumerable interface’nin generic versiyonunu kullanarak yapacağız. ArrayList örneğinde de benzer bir durum söz konusuydu, içeride object tipinden elemanlar bulunduğu için, yaptığımız her atamada uygun bir tipe cast etmemiz gerekmekteydi. Dolayısıyla aynı tipten nesneleri bir arada tutmak için generic olan List<T> koleksiyonunu kullanmayı tercih etmiştik.

Daha önceki örneklerdeki gibi Urun sınıfı üzerinden gideceğiz. UrunYonetim adında bir sınıf daha yazacağız ve bu sınıf arka tarafta bir Urun dizisi tutacak. Daha sonra da bu tip üzerinden iterasyon yapmaya çalışacağız.

foreach iterasyonu başlıklı makalemizde generic olmayan IEnumerable interface’inden detaylı olarak bahsettiğimden dolayı direkt olarak generic kullanımının örneğine geçmek istiyorum. Aynı örneği generic interface kullanarak yapacağız.

public class Urun

    {

        public int Id { get; set; }

        public string Ad { get; set; }

        public double Fiyat { get; set; }

 

        public Urun(int id, string ad, double fiyat)

        {

            Id = id;

            Ad = ad;

            Fiyat = fiyat;

        }

    }

Arka tarafta Urun sınıfını kapsülleyen ve iterasyon yapılabilen UrunYonetim adlı sınıfı tasarlayalım.

public class UrunYonetim : IEnumerable<Urun>

    {

        Urun[] urunler;

 

        public Urun[] Urunler

        {

            get { return urunler; }

            set { urunler = value; }

        }

 

        private Urun[] UrunleriGetir()

        {

            return new Urun[]

            {

                new Urun(1,"Monitör",200),

                new Urun(2,"Klavye",80),

                new Urun(3,"Mouse",40)

            };

        }

 

        public UrunYonetim()

        {

            Urunler = UrunleriGetir();

        }

 

        public IEnumerator<Urun> GetEnumerator()

        {

            for (int i = 0; i < Urunler.Length; i++)

                yield return Urunler[i];

        }

 

        IEnumerator IEnumerable.GetEnumerator()

        {

            return this.GetEnumerator();

        }

    }

Burada dikkat edilmesi gereken nokta, generic olan interface’I implement ettiğimizde sınıfa gelen iki üyedir. Birisi IEnumerable<T> ile gelen üyedir. İkincisi ise IEnumerable sınıfı ile gelen üyedir. Generic versiyonu kullanmamız halinde, generic olmayan versiyonun da uygulanması zorunlu kılınmış. Çünkü 2005 öncesinde generic mimari yoktu ve foreach iterasyonu için IEnumerable interface’i zorunluydu. Ancak generic mimari ile birlikte IEnumerable<T> zorunlu hala geldi. Örneğin string tipi IEnumerable<char> tipini implement etmiştir. Dolayısı ile generic mimariden sonra, eski kodlar geçerliliğini yitirecekti. Bu sebepten dolayı, generic interface’i implement eden tüm üyerele IEnumerable interface’ini implement etme zorunluluğu getirilmiştir.  Dolayısı ile iki üyeye de gövde kazandırmamız gerekiyor. Metotların isimleri de aynı olduğundan dolayı, TipAdi.UyeAdi notasyonu kullanılmış. İçerisinde de, generic olan IEnumerable metodu ile gelen üyeyi çağırdık.

Şimdi de Main metodu içerisinde iterasyonu sağlayıp geriye dönen elemanları inceleyelim.

static void Main(string[] args)

        {

            UrunYonetim dukkan = new UrunYonetim();

 

            IEnumerator<Urun> e = dukkan.GetEnumerator();

 

            while (e.MoveNext())

            {

                Console.WriteLine(e.Current.Ad);

            }

        }

dukkan işaretçisi üzerinden GetEnumerator metodu çağırıldığında geriye Iterasyonu yapan IEnumerator sınıfı döner. Bunun da generic versiyonu kullanılmıştır. yield operatörü sayesinde arka tarafta IEnumerator<Urun> interface’ini implement eden bir sınıf oluşmaktadır. Dolayısı ile Current property’si geriye object değil Urun tipini dönmektedir. Bu sayede de tip güvenliğini sağlamış oluruz.



1 yorum:

c# dersleri dedi ki...

Gayet açıklayıcı bir makale olmuş teşekkürler.

Yorum Gönder