Makale Özeti

"VB.NET biliyorum C# da öğrenmek istiyorum." diyenler için bir makale dizisi.

Makale

VB.NET 'den C#'a - 11

Delegate

Delegate'ler bir metodun referansını taşıyan sınıflardır. Delegate'ler metodların yapısını belirleyen türlerdir. Bir delegate tanımlayıp delegate'a metodun adresini atayıp, daha sonra delegate değişkenini kullanarak metodu çağırabilirsiniz.

Delegate'ler bir sınıfın içinde yada dışarıda tanımlanabilir, zira delegate'ler de bir türdür.

VB.NET

Public Delegate Sub Logla(ByVal str As String)

Public Class TextFileLogger

    Public Sub AddLog(ByVal str As String)

        '...

    End Sub

End Class

Yukarıdaki bir Logla adında bir delegate tanımlaması yapılmıştır. Bu delegate geriye değer dönmeyecek (yani sub), parametre olarak bir string değer alacak.

Ayrıca TextFileLogger adında bir sınıf oluşturulmuş, bu sınıf içerisinde AddLog adında bir sub var. Burada delegate'in yapısı ile AddLog metodunun yapısının aynı olması kilit nokta. Bir delegate'in bir metodu temsil edebilmesi için metodun yapısının delegate ile aynı olması gereklidir.

        Dim logger As New TextFileLogger

        Dim d As New Logla(AddressOf logger.AddLog)

        d("yeni log kayıdı")

Yukarıdaki kod bloğunda TextFileLogger sınıfından yeni bir nesne oluşturuluyor, sonraki satırda ise delegate türünde d adında bir tanımlama yapılıyor. Delegate yapılandırıcı parametresi olarak göstereceği metodun adresini alabilir. VB.NET'de metodun adresini alabilmek için AddressOf operatörü kullanılır. Daha sonra delegate üzeirnden logger nesnesinin AddLog metodu çalıştırılıyor.

VB.NET İkinci satırı aşağıdaki şekilde de yazmamıza olanak sağlar.

        Dim logger As New TextFileLogger

        Dim d As Logla = AddressOf logger.AddLog

        d("yeni log kayıdı")

Aynı işlemi C# ile aşağdaki şekilde yazabiliriz.

C#

        public delegate void Logla(string str);

        public class TextFileLogger

        {

            public void AddLog(string strmsg)

            {

                //...

            }

        }

Kullanım:

            TextFileLogger logger=new TextFileLogger();

            Logla d=new Logla(logger.AddLog);

            d("yeni log kayıdı. C#'ile");

Delegate ile metodun yapısı aynı olmalıdır derken aldığı parametre isimlerinin aynı olmasından bahsetmiyoruz. Parametrelerin türleri ve sırasının aynı olması ve metodun dönüş türünün aynı olması gereklidir.

Event

VB.NET'de event tanımlamak için iki yöntem uygulanabilir. İlk yöntem delegate ve eventi ayrı ayrı tanımlamak, ikincisi ise event'i delegate tanımlamadan tanımlamak. İkinci yöntemde compiler bizim için uygun yapıda delegate'i oluşturmaktadır.

Public Delegate Sub Connecting(ByVal state As String)

Public Delegate Sub Connected()

 

Public Class Pop3Checker

    Public Event OnConnecting As Connecting

    Public Event OnConnected As Connected

    Public Sub CheckMail()

        RaiseEvent OnConnecting("Bağlanılıyor.")

        '...

        RaiseEvent OnConnected()

    End Sub

End Class

Yukarıdaki örnekde Connecting ve Connected adında iki delegate tanımlanmıştır. Pop3Checker sınıfı içerisinde OnConnecting ve OnConnected adında iki event tanımlanmıştır. Bu eventlar tanımlanırken as ifadesinden sonra tür olarak az önce oluşturulan delegate'ler verilmiştir. Ardından CheckMail metodu içerisinden olaylar tetiklenmek istenirken RaiseEvent ifadesi ile olaylar tetiklenmiştir. VB.NET'de olayları tetiklemek için RaiseEvent ifadesi kullanılır.

Yukarıdaki kod bloğunu yine VB.NET ile fakat delegate tanımlamadan aşağıdaki şekilde yazabilir. Bu yöntemi VB.NET'in bir kısayolu olarak düşünebiliriz.

Public Class Pop3Checker

    Public Event OnConnecting(ByVal state As String)

    Public Event OnConnected()

    Public Sub CheckMail()

        RaiseEvent OnConnecting("Bağlanılıyor.")

        '...

        RaiseEvent OnConnected()

    End Sub

End Class

Yukarıdaki kod bloğunda eventların yapısı doğrudan event tanımlaması sırasında verilmiştir.

Event tanımlamasının C# ile gerçekleştirilmesinde, C# sadece delegate kullanarak event tanımlanmasına olanak tanır.

C#

        public delegate void Connecting(string state);

        public delegate void Connected();

        public class Pop3Checker

        {

            public event Connecting OnConnecting;

            public event Connected OnConnected;

            public void CheckMail()

            {

                OnConnecting("Bağlanıyor.");

                //...

                OnConnected();

            }

        }

Yukarıdaki kod bloğunda C# ile Connecting ve Connected adında iki delegate tanınlanmıştır. Pop3Checker sınıfı içerisinde ise OnConnecting ve OnConnected adında iki event tanımlanmıştır. C#'da olayları tetiklemek için olayın ismi bir metod çağırısı gibi yazılarak çağrılır. VB.NET'de olduğu gibi RaiseEvent gibi bir ifade yoktur.

Olayların Yakalanması

VB.NET ile olayların yakalanması(yani olay tetiklendiğinde çalışacak metodların belirlenmesi) için WithEvents ve Handles ikilisi ve AddHandler ifadesi kullanılır.

    Dim WithEvents p3 As New Pop3Checker

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        p3.CheckMail()

    End Sub

    Private Sub p3_OnConnected() Handles p3.OnConnected

        MessageBox.Show("Connected")

    End Sub

    Private Sub p3_OnConnecting(ByVal state As String) Handles p3.OnConnecting

        MessageBox.Show("Connecting" & state)

    End Sub

Yukarıda WithEvents ile tanımlanan Pop3Checker türündeki p3 değişkenin olayları Handles ifadesi yardımı ile metodlar ile ilişkilendirilmiştir. Metodların yapısının olaylarda tanımlanan yapı ile aynı olması gereklidir.

Yukarıdaki kod bloğu AddHandler ifadesi ile aşağıdaki şekilde oluşturulabilir. AddHandler ifadesi genellikle çalışma anında nesne oluşturulması ve bu nesnenin olaylarının kullanılmak istenmesi durumunda kullanılan ancak aşağıdaki senaryoda da kullanılması uygun olan yöntemdir.

    Dim p3 As New Pop3Checker

    Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        AddHandler p3.OnConnecting, AddressOf p3_OnConnecting

        AddHandler p3.OnConnected, AddressOf p3_OnConnected

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        p3.CheckMail()

    End Sub

    Private Sub p3_OnConnected()

        MessageBox.Show("Connected")

    End Sub

    Private Sub p3_OnConnecting(ByVal state As String)

        MessageBox.Show("Connecting : " & state)

    End Sub

C# ile olayların yakalanmasında uygulanan yöntem AddHandler ifadesine benzese de yazım kuralı olarak farklılık göstermektedir.

        Pop3Checker p3=new Pop3Checker();

        private void Form3_Load(object sender, System.EventArgs e)

        {

            p3.OnConnecting += new Connecting(this.p3_Connecting);

            p3.OnConnected += new Connected(this.p3_Connected);

        }

        private void button1_Click(object sender, System.EventArgs e)

        {

            p3.CheckMail();

        }

        private void p3_Connecting(string state)

        {

            MessageBox.Show("Connecting : " + state);

        }

        private void p3_Connected()

        {

            MessageBox.Show("Connected");

        }

C#'da olayları metodlar ile ilişkilendirmek için += gibi bir ifade ile olayın delegate listesine metodumuz için tanımlanmış olan bir delegate'in eklenmesi ile gerçekleştirilir.

 

Cengiz HAN
Microsoft ASP.NET MVP
cengiz@cengizhan.com