Makale Özeti

Bu makalemizde delegate tanımlamak tanımladıgımız delegate uzerinde islem yapmak ve delegate imizin tuttuğu metotların bilgilerini derinlemesine alma işlemlerini inceledik .

Makale


Bu makalemizde Delegate (Temsilciler) konusunu yakından inceleyelim. Temsilciler nedir ve biz programcılar için ne gibi avantajlar sunarlar. Temsilci tanımladıktan sonra neler yapabiliriz ve temsilcimizin tuttuğu değerleri nasıl görebilir ve daha efektif nasıl kullanırız .

Temsilciler metotlarımızın hafızadaki adreslerini işaret eden tiplerdir . Şimdi bir adet metot oluşturalım ve temsilciler konusuna geçmeden metotlarımızı biraz daha yakından inceleyelim

Public static double Topla (double a , double b )
{
return a+b;
}

Yukarıdaki şekilde statik bir metot oluşturduk tanımladığımız bu metot un bir geri dönüş tipi adı ve aldığı parametrelerin var olduğunu gördük . Yordamımızı çalıştırdık . c# metodumuzun adını gördüğü zaman hafızada metodun bulunduğu adresi arar ve ilgili metodumuzu çağırır. Tanımladığımız temsilcilerimiz de metotların yaptığı gibi kendisine verilen metodun veya metotların hafızadaki adresini tutar.

Temsilciler metotlarımıza referansta bulunurlar . Temsilcileri kullanmak veya kullanmamak aslında uygulamamızın içeriğine bağlıdır eğer yordamımızda bir event tanımı yapacak isek temsilci oluşturmalı veya olan bir temsilcimizi kullanmalıyız event lar oluşumları aşamasında bir adet temsilciye ihtiyaç duyarlar .

Temsilci oluşturmak için .

<erişim belirleyicisi > delegate [geri dönüş tipi] <temsilci adı> (eğer alıyor ise parametreleri)

Yukarı dada görüldüğü gibi bir metot tanımlamadan farksızdır . Temsilcilerimizin bize faydası bir değer veya değerleri aynı metot imzasından birkaç metot içerisinde kullanacak isek sadece temsilcimizi belirtip metotlarımızı teker ,teker çağırmak yerine temsilcimizi yazmamız yeterli olacaktır. Temsilcimiz arka alan da belirlediğimiz sıra ile bizim tanımladığımız metotlarımıza değer veya değerlerimizi iletir geri dönüş tipi var ise geriye değer dondurur .

Makale boyunca beraber temsilcileri tanımak acısından en basit hali ile geri dönüş değeri double olan ve iki adet double değer alan metotlar üzerinde işlemler yapıcağız. Daha sonra bunları bir temsilciye bağlayıp avantajları üzerinde konuşacak temsilcilerimizin tuttuğu değerler hakkında ne kadar daha fazla bilgi alabiliriz bunlara bakacağız .

Temsilcimizi oluşturalım .

Public delegate double Islemler(double a , double b);

Yukarıda Islemler delegate imizi oluşturduk bu temsilcimiz bizden geri dönüş değeri double olan ve parametre olarak iki adet double değer isteyen metotlarımızı işaret eder.

Simdi temsilcimize Topla metodumuzu bağlayalım ve kullanalım .


Public static double Topla(double a , double b ) { return a+b;} Topla metodumuzu bu şekilde düşünelim .

Islemler YeniIslem = new Islemler(Topla); seklinde tanımlama yaptığımız zaman artık Topla metodumuza ulaşmak için YeniIslem temsilcimizi kullanabiliriz .

YeniIslem.Invoke(23,1); seklinde değerlerimizi temsilcimizi ile verebiliriz . Temsilcimizde kendi içerisinde adreslerini tuttuğu metotlarımıza değerlerimizi iletecektir.

YeniIslem.Invoke(32,1);

Seklinde çalıştırdığımızı düşünelim . temsilcimiz aldığı değeri içersinde referans ettiği metot a yani topla metodumuza bildirecektir.

Invoke anahtar sözcüğü ile temsilcimiz çalıştırılabilir ama kullanılması zorunlu değildir .

YeniIslem.Invoke(12,3);
YeniIslem(12,2);

Her iki tanımlamada da temsilcimiz çalışacaktır .

Temsilcilerimize birden fazla metot işaret ettirip temsilcimizi çağırıp değer girdiğimiz zaman tanımladığımız tüm metotlarda işlemlerimizin gerçekleşmesini sağlayabiliriz .

Bu şekilde tanımlamaya Multicast delegate denmektedir . temsilcimize birden fazla metot eklemek için += operatörlerini çıkartmak için ise -= operatörlerini kullanırız . YeniIslem temsilcimize çıkart metodunu ekleyelim .

YeniIslem += Cikart ; seklinde bir tanımda temsilcimiz 2 adet metot tutmuş olur yukarda topla metodumuzu temsilcimizi örnekler iken tanımlamıştık .

Simdi sırası ile bol ve çarp metotlarımızda temsilcimize ekleyelim .

YeniIslem += Carp;
YeniIslem += Bol;

simdi temsilcimizin içerisindeki metotlarımızın bir listesini alalım . Temsilcimizin tuttuğu metotların isimlerini almak için GetInvocationList() metodundan yararlanırız. bu metot geri dönüş değeri olarak Delegate[] dizisi ister simdi gerekli tanımlamamızı yapalım .

Delegate[] Temsilcilerim = YeniIslem.GetInvocationList (); seklinde temsilcimiz içerisindeki tüm metot referanslarını Delegate dizisine atadık . simdi temsilcimizin tutuğu toplam metot sayısını bulalım ve metotlarımızın adlarını listeleyelim.

Console.WriteLine (“Temsilcimizin Tutuğu toplam Metot sayısı {0}”,Temsilcilerim.Length);

Temsilcimizin tutuğu toplam metot sayımızı almak için Length özelliğinden yaralandık simdi Temsilcimizin tuttuğu metotların isimlerini alalım .

for (int i = 0; i < Temsilcilerim.Length; i++)
{
Console.WriteLine("{0}. Metot adı {1}",i,Temsilcilerim[i].Method.Name);
}

For döngüsünü kullanarak temsilcimin içerisinde tuttuğu metotların adlarının listesini aldım . Artık istediğim metodu istediğim zaman çağırabilirim .

Örneğin temsilcim içerisindeki sadece en son eklediğim metodu çağırmak istiyorsam .

Console.WriteLine(Temsilcilerim[Temsilcilerim.Length-1].DynamicInvoke(12, 2));

Seklinde kullanmam yeterli olacaktır. peki burada neden sadece Length diye kullanmadık bu özellik benim temsilcim içerisindeki metotların toplamını vermiyor mu? bende temsilcimin en son metot unu çağırmak istiyorum diye sorabiliriz .

Evet Temsilcim.Length özelliği benim Temsilcim dizim içerisindeki toplam metot sayımı veriyor ama ilk değerini 1 olarak hesaplayıp veriyor arka alanda c# saymaya 0 dan başlar.

Length – 1 benim gerçek son metot indexer imi verir .

Burada deyinmemiz gereken başka bir konu var. DynamicInvoke(12,2); seklinde bir tanımlama yaptık temsilcimize değer atamak için ilk başta invoke() dememiz yeterli kalıyor hatta demesek bile c# ilgili metodumuzu buluyor ve değerimizi ilgili metot a iletiyordu .

DynamicInvoke (parametre alıyor ise parametrelerim ) : Temsilcinin temsil ettiği metodu çağırmak için kullanırız. GetInvocationList (); ile temsilcimiz içerisindeki değerlerimizi Delegate tipinden bir dizi ye atadığımız zaman ilgili index deki değerimizi çağırmak için kullanırız.

Simdi for döngümüz yardımı ile hangi metodun çalıştığını ve elde edilen sonuçların listesini alalım.

for (int i = 0; i < Temsilcilerim.Length; i++)
{
Console.WriteLine("{0} Metotu Calisti Sonuc {1}", Temsilcilerim [i].Method.Name, Temsilcilerim [i].DynamicInvoke(2, 2));
}

Yukarıdaki for döngümüzü adım ,adım inceleyelim .

Temsilcilerim.Length yardımı ile dizimin eleman sayısına ulaştım ve for döngüm eleman sayısından küçük olana dek çalışacak . Gerçek eleman sayım . Temsilcilerim.Length – 1 seklince bulunur eğer ben for daki şartımda <= küçük eşit olana kadar çalış deseydim . C# üzerinde System.IndexOutOfRangeException istisnai durumu ortaya çıkacaktı . bu hatanın tanımı bir dizi elemanı sayısının dışına taştığı zaman karsımıza çıkar .

Önemli not : Biz saymaya 1 den başlarız ama programsal olarak saymaya 0 dan başlanır .

For tanımımız içerisindeki tanımlamalara bakalım .

Console.WriteLine () ile işlemlerimizi ekrana bastırmak için kullandık çünkü temsilcimiz bize geri dönüş tipi double olan bir değer dondurur .

Temsilcilerim [i].Method.Name seklinde tanımlama ile Temsilci dizimizin i inci metot una ulaştık ve Name özelliği sayesinde metodumuzun adını aldık .

Temsilcilerim [i].DynamicInvoke(2,2); tanımı ile Temsilcilerim dizimizin i inci elemanına DynamicInvoke() metodunun yardımı ile değerlerimizi atadık ve ekran çıktımız aşağıdaki gibi karsımıza geldi .

Buraya kadar temsilcimizi tanımladık ve tekil olarak bir metot bağlayıp çalıştırdık multicast edip birden fazla metot için çalıştırdık ve ekrana metot adı sonucu olarak yazdık .

Peki biraz daha derinlemesine işlemler yapalım .

1. Metodumuzun bulunduğu namespace in adını alalım .
2. Metodun adını alalım .
3. istediği parametreleri yazalım.
4. public mi yoksa private mı olduklarını bulalım

kısacası biraz daha metotlarımızın içerisine dalalım ve inceleyelim . işlemlerimiz sırasında using System.Reflection namespace ini tanımladık .

for (int i = 0; i < Islemlerim.Length; i++)
{
Console.WriteLine("{0}. Metot Adı : {1}", i, Islemlerim[i].Method.Name);
Console.WriteLine("Geri Donus Tipi : {0} ",Islemlerim[i].Method.ReturnParameter);
Console.WriteLine("Metotumuzun erisim belirleyicisi {0}", Islemlerim[i].Method.IsPublic ? "Public" : "Private");
Console.WriteLine("Metotumuzun Bulundugu NameSpace Adı : {0}", Islemlerim[i].GetType().Namespace);
foreach (ParameterInfo parametreleri in Islemlerim[i].Method.GetParameters())
{
Console.WriteLine("Aldıgı Parametre Tipi : {0} Parametre Adı {1}",parametreleri.ParameterType,parametreleri.Name);
Console.WriteLine();

}
}

For döngümüz yardımı ile metotlarımızın bilgilerini aldık . simdi sırası ile inceleyelim .

1. Temsilcilerim [i].Method.Name : Temsilciler dizim içerisindeki metotlarımın adını almak için Method.Name özelliğinden faydalanılmıştır.
2. Temsilcilerim [i].Method.ReturnParameter : Temsilcilerim[i] indeksindeki metotlarımın geri dönüş tip değerlerini almak için ReturnParameter özelliği kullanılmıştır.

3. Temsilcilerim[i].Method.IsPublic ? "Public" : "Private" : Temsilcilerim dizim içerisindeki metotlarımın public olup olmadığını sorgulamak için kullandım . eğer public ise “Public” değil ise “Private” ekrana yazacaktır .


4. Temsilcilerim[i].GetType().Namespace : Temsilcilerim dizisi içerisinde tanımlı olan metotlarımın hangi namespace üzerinde isleme girdiğini yani isim uzayı adını aldım .

5. Islemlerim[i].Method.GetParameters() : Geri dönüş değeri ParameterInfo tipinden dizi seklindedir. Bu tipe ulamsak için System.Reflection namespace ini programıma tanımlamak yada uzun ,uzun yazmak zorundayım . Tanımlamadan da ParameterInfo tipine ulaşabilirim . System.Reflection.ParameterInfo[] seklinde yazmam gerekir . burada foreach iterasyonunu kullanarak ParameterInfo tipinden bir değer tanımlanmış ve foreach iterasyonu boyunca tanımladığımız değer ile işlemler yapılmıştır.
6. parametreleri.ParameterType: ParameterInfo tipinden aldığım değerlerini tipini almak için kullandık .
7. parametreleri.Name : Parametrelerin adlarını almak için name özelliğinden faydalanılmıştır.

Makale boyunca temsilcileri derinlemesine işlemeye çalışma mantığını anlatmaya çalıştım . Takıldığınız herhangi bir nokta olur ise mail yolu ile cevap yazabilirim.

cengiz.atilla@hotmail.com