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

21 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

  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 -> http://www.gencayyildiz.com/blog/cta-delegatetemsilci-ve-eventolay-kullanimi linkinden ulaşabilirsiniz. Yeni başlayanlar ve kafası karışık olanlar için Delegate ve […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*

Copy Protected by Chetan's WP-Copyprotect.