C# Delegate(Temsilci) ve Event(Olay) Kullanımı
Bu yazımda C#’ta Delegate(delege) yani temsilci ve Event yani olay konularından bahsedeceğim.Tabi şunu belirtmek istiyorum ki, yazımı sayfalara bölerek adım adım anlatmayı daha verimli buluyorum.Delegeler interface gibi tek başına bir anlamlı konu değildir.Kafanızda bu konuyu nerede kullanacağım gibisinden sorular olabilir.Ama Event konusuyla bağdaştırınca konuyu daha iyi irdeleyip anlamaya başlayacaksınız.
Delegate
Delegeler, metodların adreslerini dolayısıyla metodların kendilerini tutabilen, işaret edebilen yapılardır.
NOT : Metodlar da bellekte oluşan ve bellek adresleri olan yapılardır.
Delegeler referans tipli yapılardır.Yani nesne oluşturulabilirler.
Şimdi bir delege yapısı nasıl olur bakalım.
[Erişim Belirleyicisi] delege [geri dönüş tipi] [delege ismi] (eğer varsa parametre)
Örnek olarak aşağıdaki delege yapısını inceleyiniz.
public delegate void MyDelegeHandler(); //Geri dönüş tipi olmayan ve parametre almayan metodlar için kullanılır.
Delege temsil edeceği metoda imzası benzemek zorundadır.Yani yukarıdaki delegeye geri dönüş tipi int olan bir metod ya da parametre alan başka bir metod veremeyiz. Şunuda izah edeyim ki, delege isimlerinin sonuna Handler konmak yazılım geleneğinin adetlerindendir.Zorunlu değildir ama bu dünyanın kültürlerindendir. 🙂 Aşağıdaki delege türlerini inceleyeniz.
public delegate void MyDelegeHandler2(int a,int b); //Geri dönüş tipi olmayan ve int tipinden iki adet parametre alan metodlar için kullanılır. ---- public delegate int MyDelegeHandler3(int a,int b); //Geri dönüş tipi int olan ve int tipinden iki adet parametre alan metodlar için kullanılır. ---- public delegate string MyDelegeHandler4(); //Geri dönüş tipi string olan ve parametre almayan metodlar için kullanılır.
Buraya kadar delegenin yapısıyla ilgili bilgi verdim.Şimdi delegeyi kullanmayı görelim.
public delegate void CalismaHandler(); public void x() { MessageBox.Show("x metodu"); }
Yukarıda, bir tane geriye değer göndermeyen ve parametre almayan delegate ve bir tane geriye değer göndermeyen parametre almayan metodumuz mevcuttur.
private void Form1_Load(object sender, EventArgs e) { x(); }
İstesek x metodunu yukarıdaki gibi çağırıp çalıştırabiliriz. Peki bu x metodu CalismaHandler delegate i tarafından nasıl çalıştırılabilir? Delegate dediğimiz yapı bir referans tipli yapı olduğundan referansını tanımlamalıyız.Ve bu referansı tanımladıktan sonra o delegeden bir nesne yaratıp istediğimiz metodu çalıştırmasını sağlayabiliriz.
private void Form1_Load(object sender, EventArgs e) { CalismaHandler delege = new CalismaHandler(x); //Benim yukarıda oluşturduğum delegeden nesne yaratıyorum. }
Yukarıda “delege” isimli delege nesnesine , x metodunu çalıştıracaksın demiş olduk. Şimdi ise , “delege” isimli delege nesnesine , x metodunu çalıştıralım.
private void Form1_Load(object sender, EventArgs e) { CalismaHandler delege = new CalismaHandler(x); delege();//delege isimli delegate nesnesi üzerinden x referansını çalıştırmış olduk. }
Yukarıda formun loadında yazılan bu kod derlenip çalıştırıldığında mesaj kutusunda “x metodu” yazacaktır. Aynı şekilde aşağıdaki gibi bir çalıştırmada yapabiliriz.
private void Form1_Load(object sender, EventArgs e) { CalismaHandler delege = new CalismaHandler(x); delege.Invoke();//delegenin işaret ettiği metod, delegenin Invoke metodu aracılığıyla da çalıştırılabilir. }
Şimdi ise delege kullanımına bir örnek daha gösterelim.
public delegate int IslemYapHandler(int a,int b); public int Topla(int s1, int s2) { return s1 + s2; } public int Carp(int s1, int s2) { return s1 * s2; }
Yukarıda gördüğünüz gibi,geriye int tipinden değer gönderen ve int tipinden iki parametre alan bir tane delege,geriye int tipinden değer gönderen ve int tipinden iki parametre alan iki metod yazdım.
private void Form1_Load(object sender, EventArgs e) { IslemYapHandler delege = new IslemYapHandler(Topla); MessageBox.Show(delege(2, 3).ToString()); //veya MessageBox.Show(delege.Invoke(2, 3).ToString()); }
Ve yazdığım bu metodları “delege” isminde delegate nesnesine adreslettirdim.delege(2,3) veya delege.Invoke(2,3) diyerek, programı derleyip çalıştırdığımda ekranda 5 yazısını göreceğim. NOT:”delege” isimli delegate nesnesi hem Topla hem de Carp metodlarını adresleyebilir.Ben yukarıda sadece Topla metodunu adreslettim. Şimdi gelin Carp metodunuda “delege” isimli delegatemize adresleyelim.
delege += Carp;
“delege” isimli delegate ye Topla metodu verilmişti.Şimdi aynı delegate ye Carp metodu da adreslettiriliyor.Yani bir delege aynı anda birden fazla metodu adresleyebilir.Gördüğünüz gibi bunu ” += ” operatörüyle yapıyor.” += ” operatörü ile metod eklenirken, ” -= ” operatörüyle metod çıkartılabilir.( += in anlamı bağladır.) Şimdi eklenmiş halde bu programı çalıştıralım.Tabi kodlarımız böyle dağınık olunca anlamakta zorlanırsınız.Onun için bir kısmı yeniden derleyip yazıyorum.
IslemYapHandler delege = new IslemYapHandler(Topla); delege += Carp; MessageBox.Show(delege(2,3).ToString()); //ya da MessageBox.Show(delege.Invoke(2,3).ToString());
Eğer yukarıdaki kod bloğunu derleyip çalıştırırsanız ne olur? Sanıyorsunuz ki, delegemizin içinde iki metod var ve ikiside çalıştırılacak.Yani önce Topla metodu çalıştırılıp 5 sonucunu verecek, ardından Carp metodu çalıştırılıp 6 sonucu verilecek.Yada buna benzer durumlar olacak.. Ama sandığınız gibi değil. 🙂 (bende başta bu şekilde sanmıştım.) Sonuç olarak 6 cevabı verilecektir.Çünkü delegeye bağlanan en son metod çalışır.Burada delegemize bağlanan en son metod Carp metodumuz olduğu için, o çalışacaktır.Yani Topla metodu çalışıp, ardından Carp çalışmayacaktır.
IslemYapHandler delege = new IslemYapHandler(Topla); delege += Carp; delege -= Carp; MessageBox.Show(delege(2,3).ToString());
Yukarıdaki kod bloğunu incelerseniz eğer, delegemize önce Topla metodu ekleniyor.Sonra Carp metodu ekleniyor.En son olarak Carp metodu yeniden cıkarılıyor.Eee haliyle en son eklenen metod çalışıyorsa , en son çıkarılan metoddan bir önceki çalışmak zorundadır.Yani burada Topla metodu çalışacaktır. Bunu şöyle genelleyebilirim.A,B,C metodlarını sırasıyla delegemize bağlıyoruz.Bu durumda çalıştırdığımızda C metodu çalışacaktır.C yi çıkardığımız da, B metodu çalışacaktır.Son olarak B cıkarsa A metodu çalışacaktır.
Şimdide delegemiz içindeki tüm metodlarımız da sırasıyla gezebilmek için,delegate referansımız üzerinden GetInvocationList() metodunu kullanıyoruz.
private void Form1_Load(object sender, EventArgs e) { IslemYapHandler delege = new IslemYapHandler(Topla); delege += Carp; Delegate[] metodlarımız = delege.GetInvocationList(); foreach (Delegate item in metodlarımız) { MessageBox.Show("Metodumuzun adı : " + item.Method.Name); MessageBox.Show("Metodumuzun geri dönüş tipi : "+item.Method.ReturnType); int sonuc = (int)item.DynamicInvoke(2, 3); MessageBox.Show("Şuanki metodun sonucu : " + sonuc.ToString()); } }
Yukarıda gördüğünüz gibi delegemizin içinde Topla ve Carp metodları vardır.Delegate’imizin referansına GetInvocationList() metodunu çalıştırdığımızda,geriye Delegate[] dizisi tipinden veriler dönüyor ve ben bunları Delegate[] metodlarımız dizisine alıyorum.Foreach döngüsüyle bu dizide dolasıyorum.Bu dizideki metodların özelliklerine(adı,geridönüş değeri v.s.) bakabiliyorum.Burada değinmem gereken bir metod var.DynamicInvoke(),bu metod sayesinde o anda item referansına gelen metodu çalıştırabiliyoruz.Params tipinden değişken aldığı için metodların çalıştıracağı kadar parametre yazıyorum.
Bu sayfada Delegate leri görmüş olduk.Bir sonraki sayfada Event yapısından ve delegatlerle birlikte kullanımından bahsedeceğim.
Delegeler konusunu sizin anlatımınızla öğrendim.
Teşekkür ederim.
Faydalı olabildiysem ne mutlu bana,
Saygılarımla 🙂
Anlaşılır bir anlatım olmuş.
Emeğinize sağlık…
Yorumunuz içinde iltifatınız içinde teşekkür ederim..
cidden çok sade bi anlatım olmuş.. sayfa sayfa karışık anlatımlarla kıyaslayınca da çok kolay anlaşılabilir bi not olmuş. elinize sağlık
Merhaba Ahmet,
Böyle güzel yorumlarınız eşliğinde insan yaptığından ayrı bir huzur tadıyor 🙂
Teşekkürlerimi sunarım, eksik olmayın..
Tşk Ederim 3 sayfanda çok güzel anlatmışsın 🙂
ilk önce başka sitelerde okuyup anlamadığım için sinirliydim
o sinirle okuyunca senin yazınıda anlamadım şimdi tekrar okuyunca çözdün olayı teşekkürler
Aman sakin 🙂
Makale için teşekkürler. kesinlikle bir şeylerin daha iyi anlaşımlasına vesile oldunuz. 🙂
küçük bir soru. event’i classın yapıcı metot’unda fırlatmak istediğimide null dönüyor ve hata veriyor nedeni nedir acaba?
——————————————————————————————————–
class Class1
{
public delegate void sayiSay(string metin);
public event sayiSay sayiSayildi;
internal Class1()
{
string sayiSay= “Sayı”;
for (int i = 1; i ” + i.ToString());
}
}
}
———————————————————————————————————
Bu classı bir formda veya buton altında aşağıda ki oluşturun . Hata verecektir.
———————————————————————————————————
private void Form1_Load(object sender, EventArgs e)
{
Class1 cs = new Class1();
cs.sayiSayildi+= cs_sayiSayildi;
}
void cs_sayiSayildi(string metin)
{
MessageBox.Show(metin);
}
———————————————————————————————————
Cevaplarsanız memnun olurum 🙂
Merhaba,
Yazmış olduğunuz Class1 in Constructer’ında ne yaptığınız net değil. Ama dediğiniz gibi eventı yapıcı metotda fırlatıyorsanız eğer, ilgili sınıftan nesne üretildiği anda event fırlatılacak lakin olaya bağlı bir metod bulunmadığı için hata alacaksınız. Yani cs.sayiSayildi += cs_sayiSayildi komutuna gelene kadar iş işten geçmiş olacak. Bu komuttan sonra olayı fırlatmanız sorunu çözecektir.
Saygılar…
evet eksik yazmışım 🙂
for döngüsünü de bir kenara bırakın 🙂 . yapıcı metotda direk eventi direk fırlattığımızı varsayalım. bu durumda ne olursa olsun, daha nesne oluşturulurken eventi fırlattığımız için ve evente henüz bir metot bağlanmadığı için (çünkü henüz o satıra gelemedik) hata veriyor. bu durum da yapıcı metotda event tanımlayamayız diye anlıyorum ben.
ilginiz için teşekkürler.
Aynen öyle…
Tekrar bekleriz…
Tebrikler hocam. Çok açıklayıcı bir anlatım olmuş.
Teşekkürler dostum 🙂
Event kodunda mantık hatası var sanırım…
set edilmek istenen value ataması yapıldıktan sonra if kontrolüne giriyor. Yani set edilmek istenen sayı 10’dan küçük olursa yine set (atama) işlemi yapılacak ve ekrana “sayı özelliği 10dan küçük olamaz” mesajı yazdırılacak ama yinede sayı değişkenimiz 10’dan küçük değere sahip olacak.
Burada mantık hatası yok mu ? yani if koşulu ile kontrol edildikten sonra atama işlemi yapılması gerekmez mi ?
Merhaba Cüneyt Bey;
Mantıksal olarak dediğiniz gibi olması gerekmektedir 🙂 Ne hikmetse zamanında bu şekilde örnek kod yazmışım 🙂
Arada böyle oluyor. Nihayetinde aklın yolu bir. Haklısınız.
Çok güzel bir anlatım teşekkürler.
Farkli kaynaklarda delege ve eventlere birden fazla eklenince hepsinin calisacagi yaziyor.bunun nedeni c# surum farkiyla ilgili olabilir mi ? Yoksa fsrkli bir neden mi var acaba
Bir delegate eklenen tüm metotlar icra edilir, farkına varılmadan yanlış bir bilgi verilmiş sanırım. MessageBox.Show(delege(2,3).ToString()); ifadesini her bir metodun (Topla,Çarp) içerisine yazabilirseniz sonucu daha net bir şekilde alabilirsiniz.
Merhaba,
Dediğiniz gibi, delegate içerisindeki fonksiyonlar içerisinden MessageBox sınıfı çağrılabilir ve sonuç gösterilebilirdi. Lakin, bu makaleyi yazdığım yıllarda sanırım bu durumda okuduğum kaynaklar doğrultusunda ve ek olarak tarafımca yapılan tüm testler neticesinde edindiğim bilgiler bu kanıya varmama sebebiyet vermiştir. O dönem, .NET sürümünde olmayan bir özellik sonraki süreçte geliştirilmiş olabilir.
Evet…
ya da ben farkında olmaksızın yanlış bilgi vermiş olabilirim…
Nihayetinde katkılarınız için teşekkür ederim…
Daha fazla katkıda bulunmak istiyorsanız tabi ki de yapacağınız her türlü yönlendirme ve eklemelere açık olduğumu bilmenizi isterim.
Teşekkürler…
Sevgiler…
güzel
Gencay Abi merhaba öncelikle çok sade ve anlaşılır bir şekilde anlatmışsın herzaman ki gibi. O yüzden teşekkür ederim bu tarz makaleler için. Fakat şu konuda bir yanlışlık var. Makalede “Burada delegemize bağlanan en son metod Carp metodumuz olduğu için, o çalışacaktır.Yani Topla metodu çalışıp, ardından Carp çalışmayacaktır.” demişsin. Ama bu bilgi yanlış. Aslında iki metodu da çalıştırıyor ama en son ki metodun return ettiği değeri döndürüyor. Yukarıdaki Topla ve çarp metotlarının içine Console.WriteLine(“Topla çalıştı…”); gibi kod satırları yazarak görebilirsin.
Merhaba Alperen kardeşim.
Evet, o hatamı önceden uyaran arkadaşlar oldu. Bende yorumlarda yaptığımız istişareye istinaden içerikteki hatalı ifadeyi olduğu gibi bıraktım ki tartışmanın sebebi görülebilsin.
Bilgilendirmen için teşekkür ederim.
Sevgiler.
Merhaba
Gençay hocam. Sizi youtube platformunda da takip ediyorum. Sizden çok şey öğrendim. Makaleleriniz benim için daha da artı oluyor. Emekleriniz için teşekkür ederim
Merhaba,
Bol bol faydalanmanız dileğiyle…
Sevgilerimle…
Hocam anlatımız gayet anlaşıklı. Konuyu öğrenmiş oldum sadece birşeyi hala anlayamadım. Çoğunluklu olarak MVC üzerinden Web Projeleri geliştirmekteyin ara sıra Console ve Winformda kullanmışlığım oldu. Ama şimdiye kadar kendi projelerimdede hiç bir zaman delegate kullanmadım. Gerek duymadım diyebilirim. Yani en önemlisi demek istediğim metodun kendisini kullanıp gereken sonucu alabiliyorsak delegate neden kullanmalıyız. Kendinizde yazınızda
“İstesek x metodunu yukarıdaki gibi çağırıp çalıştırabiliriz” diye belirtmişsiniz
Peki bunu önemli yapan nedir ? Herhalde C# geliştiricileri bunu boşu boşuna dahil etmemişlerdir diye düşünüyorum. Yazıda buna değindiyseniz görmediysem şimdiden özür dilerim. Teşekkürler
Merhaba,
Güzel soru.
Delegate’in işlevselliği ihtiyaç noktalarında devreye farklı metotları dolaylı bir yolla sokabilmesinden gelmektedir. Böylece metotları runtime’da seçebilmemizi sağlamaktadır.
Normalde bir metodu compiler time’da bilinebilecek şekilde tetiklersiniz. Halbuki delegate’ler metotları anonim olarak çağırmanıza izin veren yapılar olduğundan dolayı, runtime sürecinde çağrılabilmektedirler. Böylece çağrılan metodun hangisi olduğunu bilemezsiniz!
Buradan anlıyoruz ki, delegate’ler işaret/temsil ettikleri metotları veri olarak gören yapılar olarak düşünülebilir. Haliyle bu veri olarak görülen metotları istediğiniz herhangi bir noktada işleyebilmektesiniz.
Peki hangi durumlarda delegate’ler ile temsil edilen metotları işlemeyi tercih ederiz? diye sorarsanız eğer;
delegate’lerden istifade edebiliriz.
Umarım cevabım meramınızı gidermeye yardımcı olmuştur.
Sevgilerimle…
Yazıda delege içerisinde bulunan tüm metotlar değilde sadece en son eklenen metod çalışıyor demişsiniz ama öyle değil bütün metotlar ekleme sırasına göre çalışıyor geri dönüş türleri varsa da en son eklenen metodun döndüğü değer dönülüyor.
Evet, bu durumu önceden yapılan yorumlarda da bazı arkadaşlarımızla istişare ederek kabullenmiş durumdayım.
Teşekkürler.