C# delegate Nedir? Kullanımı

C# içerisinde metotların adres bilgisini tutmak için kullanılan temsilci veya delegate nedir, neden kullanılır ve kullanımı ile ilgili bilgiler yer alıyor.

C# delegate nedir?

C# programlama dilinde tanımlanan ve metot olarak adlandırılan işlevlerin bellek adresini tutmak için kullanılan yapıya delegate veya temsilci denir.

C# delegate yapısı C ve C++ dillerinde yer alan function pointer veya fonksiyon göstericilerine benzemektedir.

Bilgisayar üzerinde işlem yapan her şey (değişkenler, sınıflar, metotlar) bellek üzerinde tutulur.

Bizler genellikle bellekte tutulan değişken değerleri üzerinde işlem yaparız.

C# programlama dilinde int, float, double, char, byte gibi verilerin bellekte tutulmasını ifade eden veri türleri yer alır.

Örneğin; C# dilinde yer alan byte bellekte 8 bitlik yer kullanır.

using System;

class Program {

    static void Main() {

        byte BirSayi = 55;
        Console.WriteLine(BirSayi);
    }
}

Kullandığımız bu tanımlar C# dilini geliştirenler tarafından belirlenmiştir.

Metotlarda bellekte tutulduğu için metotların adresine de erişebiliriz.

Ancak metotlarda bu durum biraz daha farklıdır.

Çünkü metotların sabit bir tanımı yoktur.

Aşağıda bulunan her iki metot birbirinden farklıdır.

void Topla(int sayi1, double sayi2);
void Topla(double sayi1, int sayi2);

Sadece metotların parametre sırası değişmesine rağmen metotlar farklıdır.

NOT: Metot adı ve parametresi metot imzası olarak adlandırılır.

Bellekte bulunan metotlara erişebilmek için metot imzasının bilinmesi gerekir.

Bu metot imzası C# içerisinde yer alan delegate ile tanımlanır.

C# delegate kullanımı

Genel tanım aşağıdaki gibidir.

delegate <Metot-Dönüş-Değeri> <Temsilci-Adı>(<Metot-Parametresi>);

Yukarıda tanımlanan ilk metoda erişmek için aşağıdaki gibi bir delegate tanımı yapılması gerekir.

// Metot imzası temsil ediliyor.
delegate void Temsilci(int sayi1, double sayi2);

İkinci metoda erişmek için ise aşağıdaki gibi tanımlama yapılması gerekiyor.

delegate void Temsilci2(double s1, int s2);

Not: Parametre isimlerinin bir önemi yoktur sadece veri türlerinin eşleşmesi yeterli olacaktır.

Oluşturduğumuz temsilci sayesinde bu imzaya sahip metotlara erişebiliriz.

Metotlara erişim aşağıdaki gibidir.

using System;

class Program {
    delegate void Temsilci(int s1, double s2);

    static void Main() {
        Temsilci Metot = Topla;  // Temsilci Metot = new Temsilci(Topla);
        Metot(7, 77);
    }

    static void Topla(int sayi1, double sayi2) {
        Console.WriteLine("Sayı1: {0} - Sayı2: {1} - Sonuç: {2}", sayi1, sayi2, sayi1 + sayi2);
    }
}

Tanımlanan temsilci değişkeninin parantez () ile çağrıldığına dikkat edin!

Bir temsilci birden fazla metoda (Multi Delegate) erişim için kullanılabilir.

using System;

class Program {
    delegate void Temsilci(int s1, double s2);

    static void Main() {
        Temsilci Metot = Topla;  // Temsilci Metot = new Temsilci(Topla);
        Metot += Carp;
        Metot = Metot + Topla;
        Metot -= Topla;
        Metot(7, 77);
    }

    static void Topla(int sayi1, double sayi2) {
        Console.WriteLine("Sayı1: {0} - Sayı2: {1} - Sonuç: {2}", sayi1, sayi2, sayi1 + sayi2);
    }

    static void Carp(int sayi1, double sayi2) {
        Console.WriteLine("Sayı1: {0} - Sayı2: {1} - Sonuç: {2}", sayi1, sayi2, sayi1 * sayi2);
    }
}

Ekleme işlemi için + ve += operatörünün kullanıldığına dikkat edin!

Eklenen metotları çıkarmak içinse – veya -= operatörü kullanılır.

Neden kullanılır

C# içerisinde yer alan delegate yapısı genellikle bellekteki metotların bir olay sonucu çalıştırılması için kullanılır.

Örneğin veritabanından bir kayıt silindiğinde bir metodun çalıştırılması, dosya silindiğinde bir metodun çalıştırılması delegate ile yapılır.

WinForms, WPF ve UWP gibi görsel arayüzler kullanırken bir button nesnesine tıklandığında bir metodun çalıştırılması buna örnek olarak verilebilir.

Visual Studio IDE ile yeni bir Windows Forms Application projesi oluşturup form alanına çift tıklandığında Form1_Load metodu oluşur.

Bu metot Form sınıfında yer alan Load isimli temsilci tetiklendiğinde çalışacaktır.

Metot ekleme işlemini görmek için Form1.Designer.cs dosyasına bakıldığında aşağıdaki gibi tanım göreceksiniz.

this.Load += new System.EventHandler(this.Form1_Load);

Aslında sınıf içerisinde olayların yönetimi için delegate tanımlamamıza gerek yoktur.

Bu işlem için .NET içerisinde yer alan EventHandler temsilcisi kullanılabilir.

Bu temsilci object ve EventArgs türünden parametre alır.

İlk parametrenin object türünden olmasının nedeni tüm C# nesnelerinin object türünden türemiş olmasından dolayıdır.

İkinci parametre ise olay sonucunda çalıştırılacak metoda olay ile ilgili bilgi vermek için kullanılır.

Oluşturulan Form projesinin MouseClick olayı oluşturulduğunda EventArgs sınıfından türetilerek özelleştirilen MouseEventArgs sınıfının kullanıldığı görülür.

MouseEventArgs sınıfı tıklama yerini (X, Y) hangi tuşla tıklandığı (Button) gibi bilgileri saklar.

C# delegate ile hazırlanmış sınıf örnekleri aşağıda yer almaktadır.

/*
*   Author : Yusuf SEZER
*   Copyright (c) www.yusufsezer.com.tr
*/
using System;
using System.IO;

class Program {

    static void Main() {

        DosyaIslemleri islem = new DosyaIslemleri("abc.txt");
        islem.DosyaSilindiginde += MetotCalistir;
        islem.DosyayiSil();
    }

    static void MetotCalistir(object sender, SonucArgs e) {
        Console.WriteLine("Dosya: {0}", e.Dosya);
        Console.WriteLine("Mesaj: {0}", e.Mesaj);
        Console.WriteLine("Tarih: {0}", e.Tarih);
    }
}

class SonucArgs : EventArgs {
    public string Dosya;
    public string Mesaj;
    public DateTime Tarih;

    public SonucArgs(string dosya, string mesaj, DateTime tarih) {
        this.Dosya = dosya;
        this.Mesaj = mesaj;
        this.Tarih = tarih;
    }
}

class DosyaIslemleri {
    private string Dosya;
    public EventHandler<SonucArgs> DosyaSilindiginde;  // event

    public DosyaIslemleri(string dosya) {
        this.Dosya = dosya;
    }

    public void DosyayiSil() {
        if (File.Exists(this.Dosya)) {

            File.Delete(this.Dosya);
            if (this.DosyaSilindiginde != null) {
                this.DosyaSilindiginde(this, new SonucArgs(this.Dosya, "Dosya silindi.", DateTime.Now));
            }
        }
        else {
            if (this.DosyaSilindiginde != null) {
                this.DosyaSilindiginde(this, new SonucArgs(this.Dosya, "Dosya olmadığından dolayı silinemedi.", DateTime.Now));
            }
            // this.DosyaSilindiginde?.Invoke(this, new SonucArgs(this.Dosya, "Dosya olmadığından silinemedi.", DateTime.Now));
        }
    }
}

Sınıflardaki olayların yönetilmesi için event anahtar kelimesinin eklenmesi faydalı olacaktır.

Event anahtar kelimesi ile ilgi bilgiye .NET Dersleri bölümünden ulaşabilirsiniz.

Burada neden SonucArgs sınıfı tanımlarız gibi bir soru gelebilir.

Bunun temel nedeni Nesne Yönelimli Programlamada yer alan sorumlulukların ayrılması prensibidir.

SonucArgs sınıf ile gönderilen parametreler DosyaIslemleri içerisinde tanımlanabilir.

Ancak birden fazla olayın bulunduğu sınıflarda tanımlama fazla olacak ve sınıfın gereksiz yere genişlemesine neden olacaktır.

Temsilcilerin diğer bir kullanım nedeni ise işlem sonuçlarının kayıt altına (log) alınmasıdır.

Büyük çaplı projelerde veritabanı işlemleri sırasında silinme işleminin yapıldıktan sonra kayıt altına alınması bu yöntemle sağlanabilir.

C# Derslerine buradan ulaşabilirsiniz.

Hayırlı günler dilerim.

Yusuf SEZER

Yusuf SEZER

Computer Engineer who interested about web technologies, algorithms, artificial intelligence and embedded systems; constantly exploring new technologies.


Bunlara'da bakmalısın!