19 Eylül 2011 Pazartesi

C# Indexer Property

Indexer, özel bir tip property’dir. Yazıldığı sınıfa indexleyici özellik kazandırır. Dizilerde ve bazı koleksiyonlarda köşeli parantezler ile index verebilmemiz, bu property sayesindedir. İlk olarak Framework’de var olan ArrayList üzerinde inceleme yapalım, ardından kendi yazdığımız tiplere nasıl indeksleyici kazandırabileceğimizi inceleyeceğiz.

ArrayList tipinden bir nesne örnekleyerek içerisine eleman ekleyelim.

class Program

    {

        static void Main(string[] args)

        {

            ArrayList arrayList = new ArrayList();

            arrayList.Add("istanbul");

            arrayList.Add("ankara");

            arrayList.Add("izmir");

            arrayList.Add("bursa");

        }

    }

arrayList nesnesi üzerinden köşeli parantez açtığımızda,

Untitled

parametre olarak integer alan ve geriye object dönen bir üye söz konusu. Şimdi de ArrayList üzerinden Go to definition diyelim. Aşağıdaki görüntü ile karşılacağız.

Untitled

İşte gördüğümüz bu üye, ArrayList tipine indexer özelliğini kazandıran üyedir. get ve set bloklarından da anlaşılacağı gibi, bu üye bir property’dir. Ancak özel bir üyedir, adı “this” olmak zorundadır ve parametre almalıdır. Aşırı yüklenebilirler(overload edilebilir).

Kendi yazdığımız tiplerde indexer kullanabilmemiz için adı this olan ve parametre alan bu özel üyeyi eklememiz gerekmektedir. Şimdi Urun adında bir sınıf tasarlayalım, daha sonra da UrunYonetim adında bi sınıf tasarlayalım ve yapıcı metodunda bir Urun dizisi oluşturalım (ArrayList’in arka tarafta oluşturduğu object dizisi gibi). Oluşturduğumuz UrunYonetim sınıfının, içerisinde foreach ile gezilebilen bir tip olabilmesi için IEnumerable interface’ini implement edelim.

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;

        }

    }

 

    class UrunYonetim : IEnumerable

    {

        public Urun[] UrunSepeti { get; set; }

 

        public UrunYonetim()

        {

            UrunSepeti = new Urun[]

            {

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

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

                new Urun(3,"Mouse",40)

            };

        }

 

        public IEnumerator GetEnumerator()

        {

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

                yield return UrunSepeti[i];

        }

    }

Indexer kullanımını sağlayan özel üyeyi bilmediğimizi varsayalım. UrunYonetim tipinden bir nesne örneklediğimizde indexleyici kullanmak istersek, aklımıza framework’de var olan ve indexer özelliği olan tipler gelir. Yani bir ArrayList nesnesi örnekleyerek, UrunYonetim içerisindeki diziyi bu nesne örneği ekleyebiliriz ve indeksleyici kullanabiliriz.

class Program

    {

        static void Main(string[] args)

        {

            UrunYonetim dukkan = new UrunYonetim();

 

            ArrayList arrayList = new ArrayList();

            foreach (Urun u in dukkan)

            {

                arrayList.Add(u);

            }

 

            Console.WriteLine(((Urun)arrayList[0]).Ad);

 

        }

    }

Burada iki dezavantajımız var. Birincisi, ram’e fazladan bir ArrayList örneği çıkararak iterasyon ile elemanları eklemek zorunda kaldık. Dolayısı ile ram’deki iş yükü artmış oldu. İkincisi de, arrayList indexleyici’si geriye object döndürdüğü için cast işlemi yapmak zorunda kaldık. Halbuki bizim UrunYonetim sınıfını yazmamızın amacı, arka tarafta bir Urun dizisi kapsüllemekti. Yani geriye bir Urun döneceğinden eminiz. İşte bu sebeplerden ötürü kendi sınıfımıza indexer özelliği kazandırmak yararımıza olacaktır. UrunYonetim sınıfına aşağıdaki üyeyi ekleyelim.

public Urun this[int index]

    {

        get { return UrunSepeti[index]; }

        set { UrunSepeti[index] = value; }

    }

Artık dukkan adlı nesne örneğine bir index verdiğimizde geriye, parametre olarak verilen index değerine sahip ürünü dönecektir.

class Program

    {

        static void Main(string[] args)

        {

            UrunYonetim dukkan = new UrunYonetim();

 

            //ArrayList arrayList = new ArrayList();

            //foreach (Urun u in dukkan)

            //{

            //    arrayList.Add(u);

            //}

 

            //Console.WriteLine(((Urun)arrayList[0]).Ad);

 

            Console.WriteLine(dukkan[0].Ad);

 

        }

    }

Untitled

Eklediğimiz üye sayesinde, yorum satırı olarak işaretlenen kısımda yapılan işlere gerek kalmadı. İndexer üyenin aşırı yüklenebilir olduğunu söylemiştik. Şimdi de parametre olarak string bir değer alan, ve girilen string ile aynı isme sahip ürünün fiyatını geriye döndüren bir üye yazalım. (Urun dizisi içerisindeki her bir ürünün adının unique olduğunu varsayalım.)

public double this[string name]

    {

        get

        {

            foreach (Urun u in UrunSepeti)

            {

                if (u.Ad.ToLower() == name.ToLower())

                {

                    return u.Fiyat;

                }

            }

 

            throw new IndexOutOfRangeException("ürün bulunamadı");

        }

    }

İsimleri karşılaştırırken, küçük-büyük harf sıkıntısı yaşamamak için ToLower() metodunu kullandık. Main metodu içerisinde,

Console.WriteLine(dukkan["monitör"]);

Untitled

Görüldüğü gibi, kendi yazdığımız tiplere indexer özelliğini kazandırmak son derece kolay. Faydalı olması dileği ile…



4 yorum:

Adsız dedi ki...

örnek için çok teşekkürler, gayet açıklayıcı fakat sormak istediğim bir şey var; yeni ürünleri nasıl ekleyeceğim main metodu içersinde?

Onur Salkaya dedi ki...

Sormak istediğinizi tam olarak anlayamadım. Ancak indexer ile okumak yapmak yerine, eleman ekleme işlemini kastediyorsunuz sanırım. Nasıl ki;

int[] dizi = new int[5];
dizi[0] = 5;

şeklinde bir ekleme yapabiliyorsak, yeni bir elemanı da aynı şekilde ekleyebilirsiniz. Çünkü indexer özel bir tip property'dir, get bloğunu kullanarak okuma yaptığımız gibi, set bloğunu kullanarak atama da yapabiliriz. Yani;

dukkan[indexDegeri] = .... gibi bir tanımlama yaparsak, set bloğu çalışacak ve istediğimiz değer atanacaktır

Adsız dedi ki...

cevap için teşekkürler,

Adsız dedi ki...

Anlatımlarınız sade ve anlaşılır. Teşekkürler..

Yorum Gönder