Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

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.

Bunlar da hoşunuza gidebilir...

35 Cevaplar

  1. woodgreen dedi ki:

    Delegeler konusunu sizin anlatımınızla öğrendim.
    Teşekkür ederim.

  2. gtroant dedi ki:

    Anlaşılır bir anlatım olmuş.
    Emeğinize sağlık…

  3. ahmet dedi ki:

    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

    • Gençay dedi ki:

      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..

  4. Cihan dedi ki:

    Tşk Ederim 3 sayfanda çok güzel anlatmışsın 🙂

  5. Sefa Gündüz dedi ki:

    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

  6. murat dedi ki:

    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 🙂

    • Gençay dedi ki:

      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…

      • murat dedi ki:

        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.

  7. Yusuf dedi ki:

    Tebrikler hocam. Çok açıklayıcı bir anlatım olmuş.

  8. Cüneyt dedi ki:

    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 ?

    • Gençay dedi ki:

      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.

  9. İbrahim dedi ki:

    Çok güzel bir anlatım teşekkürler.

  10. mustafa dedi ki:

    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

  11. Bekir Otrkc dedi ki:

    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.

    • Gençay dedi ki:

      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…

  12. ertuğ dedi ki:

    güzel

  13. Alperen dedi ki:

    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.

    • Gençay dedi ki:

      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.

  14. Fatih Uyanık dedi ki:

    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

  15. Akhmad dedi ki:

    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

    • Gençay dedi ki:

      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;

      • .NET’te callback fonksiyonları oluşturmak istediğimizde,
      • Birden fazla metodu sırayla tetiklemek istediğimizde,
      • Asenkron operasyonlar gerçekleştirmek istediğimizde

      delegate’lerden istifade edebiliriz.

      Umarım cevabım meramınızı gidermeye yardımcı olmuştur.
      Sevgilerimle…

  16. Hüseyin CUMA dedi ki:

    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.

  17. Nazmi ACAR dedi ki:
    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());
        }
    }
    

    Çalıştırdığımda ” ‘System.Int32’ türündeki nesne ‘System.Int16’ türüne dönüştürülemez.” hatası alıyorum.

    Platform Visual Studio 2012 ve .Net Framework 4.5

    Teşekkür ederim.

  1. 13 Nisan 2016

    […] Design Pattern makalesininde sonuna gelmiş bulunmaktayız. Konumuzu noktalamadan önce delegate – event yapıları arasındaki ilişki ile Observer tasarım şablonundaki subject ve aboneler arasındaki […]

  2. 18 Şubat 2018

    […] ve event kullanımı başlarda zor olsa da aslında oldukça basit. Detaylı anlatıma -> https://www.gencayyildiz.com/blog/cta-delegatetemsilci-ve-eventolay-kullanimi linkinden ulaşabilirsiniz. Yeni başlayanlar ve kafası karışık olanlar için Delegate ve […]

  3. 06 Ocak 2020

    […] odaklanacağız. Bunun için yazımızın ileriki satırlarında da görebileceğiniz üzere delegeleri […]

Cihan için bir yanıt yazın Yanıtı iptal et

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir