Makale Özeti

Delegate bir prosedürün çağrılabilirliğini belirleyen ve bu prosedürün çağrılmasını sağlayan bir yapıdır. Bu makalede delegate kavramını örnekle anlamaya çalışacağız.

Makale

DELEGATE KAVRAMI  

Bazı durumlarda bir metoda parametre olarak bir prosedürü aktarabilmek işlerimizi büyük ölçüde rahatlatabilir. Örneğin “genel” sıralama prosedürlerinde söz konusu durum kullanılabilir. Genel sıfatını biraz açalım; öyle bir sıralama prosedürü geliştirelim ki bu prosedür iki parametre alsın. İlk parametre sıralanacak bilgileri kabul etsin.İkinci parametre ise neye göre sıralama yapacağını belirleyecek karşılaştırma kriterini yine bir prosedür olarak alabilsin.  Bu sayede sadece kriteri değiştirerek (genel sıralama prosedürünü değiştirmeden) sıralamayı istediğimiz kritere göre kullanabilelim.   

“Müşteriler” nesnesini ada göre sıralayan ya da “Satış” nesnesini tarihe göre sıralayan prosedürler yazmak gayet kolay. Ama düşünün ki; sıralama yapılabilecek onlarca hatta yüzlerce kriter olabilir. Her kriter için aynı kodu küçük değişikliklerle kopyalayıp yapıştırmak bir çözüm olabilir :) Ama biz burada daha profesyonel bir çözüm geliştireceğiz. Genel bir sıralama prosedürünü keyfi kriterlere göre sıralama yapabilecek şekilde tasarlayacağız.

Bunun için delegate’leri kullanacağız. Böylelikle delegate kullanımını uygulama üzerinde kavramaya çalışacağız.

Delegate kavramını en genel biçimde şöyle tanımlayabiliriz; delegate bir prosedürün çağrılabilirliğini belirleyen ve bu prosedürün çağrılmasını sağlayan bir yapıdır.

Delegate Tanımlama;
Bir delegate tanımlanırken aslında çağrılabilecek prosedürün yapısı belirlenir.Bu yapıyı görebilmek için her türlü veriyi sıralayabilecek bir modül tasarlayalım.Bunun için yeni bir Windows Application projesi oluşturun ve “Sirala” adında bir modül ekleyin.Modüle şu kodu yazın.

Public Delegate Function Karsilastir(ByVal v1 As Object, ByVal v2 As Object) As Boolean

Bu tek satırlık kod aslında hayli ilginç bir iş yapıyor:  bir metodun “yapısını” bir “veri türü” olarak tanımlıyor. Bu yeni veri türünün adını “Karsilastir” olarak belirliyor. Bu sayede bu veri türünü kullanarak değişken tanımlamamız yada herhangi uygun bir metoda bu veri türünü parametre olarak aktarabilmemiz sağlanıyor.

Bu veri türü kullanarak oluşturulan parametre yada değişkenler aslında, belirtilen “yapı”daki asıl metodun adresini tutarlar. Bu asıl metodu oluşturduğumuz değişken tarafından çağırabiliriz.


Delegate kullanarak oluşturulan veri türünü kullanma:
Şimdi yazacağımız prosedür asıl sıralama işlemini yapacak kısım. Burada dikkat edilmesi gereken nokta parametre olarak (delegate ile oluşturulan)  “Kiyasla” veri türünü kabul etmesi. Aynı modüle şu kodları yazın:

Public Sub SiralamaYap(ByVal veri As Object, ByVal denBuyuk As Karsilastir) 
        Dim dis As Integer 
        Dim ic As Integer 
        Dim temp As Object 
        For dis = 0 To UBound(veri) - 1 
            For ic = dis + 1 To UBound(veri) - 1 
                If denBuyuk.Invoke(veri(dis), veri(ic)) Then 
                    temp = veri(dis) 
                    veri(dis) = veri(ic) 
                    veri(ic) = temp 
                End If 
            Next 
        Next 
        klasik bir sıralama algoritması uyguladık.
End Sub

Burada birkaç noktanın altını çizelim;

* “denBuyuk” parametresine dikkat edin. Bu değişken “Kiyasla” delegate’inin tanımlamış olduğu “yapı”yla eşleşen bir metodun adresini tutar. Diğer bir deyişle Sirala prosedürüne, delegate ile eşleşen yapıdaki herhangi bir metot parametre olarak aktarılabilir.

*Delegate’in Invoke metodunun nasıl çağrıldığına da dikkat edin.

*Prosedürün sıralamayı object veri türü üzerinden yaptığına dikkat edin. Object veri türü her şeyi adresleyebileceğinden sıralanmak istenen şey karakter katarından sayı dizisine, gezegenlerden klavye tuşlarını sıralamaya  :)  aklınıza gelebilecek her şey olabilir. Sıralamanın nasıl yapılacağını ise parametre olarak aktardığımız delegate’e bırakılıyor.

Delegate metodu oluşturma:
Şimdi yapmamız gereken delegate metodu oluşturmak  ve sıralama prosedürümüzü çağırmak. Bunun için delegate’in belirttiği “yapı”da metotlar oluşturmamız gerekiyor. Birey adında bir class oluşturun  ve şu kodları ekleyin;

Public Class Birey

    Private mAd As String
    Private mTarih As Date
yerel değişkenler
    Public Sub New(ByVal Ad As String, ByVal DogumTarihi As Date)
        mAd = Ad
        mTarih = DogumTarihi
     End Sub

    Public ReadOnly Property Yas() As Integer
        Get
            Return DateDiff(DateInterval.Year, mTarih, Now())
        End Get
    End Property
bireyin yaşını döndüren metot

    Public Property Ad() As String
        Get
            Return mAd
        End Get

        Set(ByVal Value As String)
            mAd = Value
        End Set
    End Property
bireyin adına atama yapabilen/döndürebilen metot

    Public Shared Function YasaGoreSirala(ByVal birey1 As Object, ByVal birey2 As Object) As Boolean

        Return CType(birey1, Birey).Yas > CType(birey2, Birey).Yas  
    End Function

     Public Shared Function AdaGoreSirala(ByVal birey1 As Object, ByVal birey2 As Object) As Boolean

        Return CType(birey1, Birey).Ad > CType(birey2, Birey).Ad  
    End Function

End Class

Burada oluşturduğumuz fonksiyonlara dikkat! Bu fonksiyonlar sadece, ilk nesne ikincisinden büyükse "true" değerini dönderiyorlar. Sıralama adına herhangi bir iş yapmıyorlar. Tek yaptıkları asıl sıralama prosedürümüze gerekli olan kıyaslama kıstasını belirlemek oluyor.

Dikkat ederseniz bu fonksiyonların yapısı delegate’in yapısıyla aynı. Her ikisi de (-fonksiyonlar ve delegate-) iki adet “object” türünde veriyi parametre olarak alıyor ve ikisi de sonuç olarak “boolean” bir ifade dönderiyor. Bu eşlemenin (yapı eşleşmesinin) sağlanmasının şart olduğunu unutmayın. (Ayrıca fonksiyonlar parametre olarak "object" veri türünü aldığından ctype ile tip dönüşümü yaptık!)

 Buraya kadar birbirinden bağımsız delegate(“Karsilastir”) ve delegate’in yapısında metotlar (“AdaGoreSirala”, ”YasaGoreSirala”) oluşturduk. Şimdi bu ikisi arasındaki ilişkiye belirlememiz gerekiyor. Bunun için AddressOf operatörünü kullanacağız. AddressOf herhangi bir prosedürün adresini döndürür. Bu sayede parametre olarak delegate kabul eden prosedürlere bu operatörden dönen değeri verebiliriz. Form1e bir button yerleştirin. Adını "Sırala" olarak değiştirin. Aşağıdaki kodları buttonun yordamına ekleyin.

        Dim Calisanlar(5) As Birey
        Calisanlar(0) = New Birey("Öznur", #1/1/1984#)
        Calisanlar(1) = New Birey("Kâsım", #1/1/1983#)
        Calisanlar(2) = New Birey("Bilâl", #1/1/1982#)
        Calisanlar(3) = New Birey("Mustafa", #1/1/1981#)
        Calisanlar(4) = New Birey("Erkam", #1/1/1980#)
        birey tipinde bir dizi oluşturduk ve isim-doğum tarihi atamaları yaptık

        SiralamaYap(Calisanlar, AddressOf Birey.AdaGoreSirala)
        sıralamayı yapan kısım  

        Dim objBirey As Birey
        Dim i As Integer
        For i = 0 To UBound(Calisanlar) - 1
            objBirey = Calisanlar(i)
            System.Diagnostics.Debug.WriteLine(objBirey.Ad & " " & objBirey.Yas)
        Next
        yazdırma işlemini yapan kısım

İlk  bölümde "calisanlar" adında bir dizide bireylerimizi topladık.Son bölümde ise sıralanan verileri debug kullanarak outputa yazdırdık.Burada asıl dikkat edilmesi gereken nokta AddressOf operatörünün kullanılması. SiralamaYap fonksiyonu ikinci parametre olarak delegate kabul ediyordu. Buraya "Birey" sınıfımızın "AdaGöreSirala" fonksiyonunun adresini aktardık.

Bu aşamadan sonra örneğin ada göre değilde yaşa göre sırala yapmak istersek yapmamız gereken tek şey;


SiralamaYap(Calisanlar, AddressOf Birey.AdaGoreSirala)


satırını

SiralamaYap(Calisanlar, AddressOf Birey.YasaGoreSirala)

ile değiştirmek. İşte hepsi bu kadar...

Böylelikle yazının başında söylediğim metoda parametre olarak prosedür aktarma işlemini delegate kullanarak gerçekleştirmiş olduk.Umarım uygulama üzerinde delegate kullanımını aktarabilmişimdir. Altını çizmemiz gereken son bir nokta daha kaldı;

.NET  yapısı altında metotların geri çağrılmasında kullanılan asıl mekanizma delegate’lerdir.  Vb.NET’te ise kullanılan Event, RaiseEvent, WithEvents, Handles gibi kavramlarla aslında arka planda delegate’lere iş yaptırılır.

Yazı hakkında değerlendirmelerinizi bekliyorum.
Farenizin tıkı, klavyenizin tıkırı, eksik olmasın..

Kâsım Gülcan
SQLNedir?com