Delegates – Events

Merhaba,

            Bu yazıda C#’da programlamayı güçlendiren ve özellikle framework yapılarında geniş kullanım alanı olan Delegate(Temsilci) ve Event(Olay) olarak adlandırılan veri yapılarını inceleyeceğiz.

Delegate: Çeşitli metodların referanslarını temsil eden ve Event(Olay)’in işlemlerini tanımlayan bir değişkendir.

Event: Bir nesnenin, bir durum oluştuğunda program ile iletişim kurmasını sağlar. Bir olay sonucunda, bir dizi davranışın belirlenmesini sağlar.

Sayfa 1: Delegate genel kullanımı

Sayfa 2: Sistem namespace de tanımlı delegate türleri.

Bu tanımlamaları detaylı olarak açalım ve örneklerle anlayalım.

1 – DELEGATES

Delegates, metodları temsil eden bir veri türüdür. Aynı C#’daki diğer veri türleri olan char, string, int, class, interface… vb. gibi. Delegate, value(değer) tipi bir veri türüdür. İçerisinde bellekte barındırılan verinin referansını tutar.

Delegate kendisine atanan bir metodun bellekteki adresini tutar. Metodlar referans veri türleri gibi bellekte belirli bir adreste barındırılır. Her metod girişinin başlangıç adresi belirlidir. Bir delegate üzerinden metod çağrıldığında, metod başlangıç adresine gidilir ve metodun kapsamı içerisinde işlemler tamamlanır.

Bir Delegate tanımlarken aşağıdaki yapı izlenir:

[Erişim Belirleyicisi] delegate [geri dönüş tipi] [delege ismi] (varsa aldığı parametre/ler)

Burada “delegate” anahtar sözcüğü ile tanımlama yapılır ve aynı metod yapısına benzerdir; tek farkı gövdesi yoktur. Temsilci olduğundan, temsil ettiği method/ların gövdeleri kullanılır. Aşağıda bazı delegate tanımlamaları verilmiştir.

//Geriye değer döndermeyen ve parametreler alan bir delegate tanımlaması.
public delegate void SomeWorkHandler(int x,int y);

//Geriye değer döndermeyen ve parametre almayan bir delegate tanımlaması.
public delegate void SomeWorkHandler ();

//Geri dönüş tipi “int” olan, parametreler alan bir delegate tanımlaması.
public delegate int SomeWorkHandler (int x,int y);

//Geri dönüş tipi “string” olan, parametre almayan bir delegate tanımlaması.
public delegate string SomeWorkHandler ();

Delegate tanımlaması yaparken mutlaka temsil edeceği method veya methodların imzası ile aynı olmalıdır. Yani, methodun geri dönüş tipi ve aldığı parametrelerin adedi ve türleri tanımlanan delegate ile eşleşmelidir.

Burada isimlendirmeler önemli değildir. Ancak delegate tanımlamasında verilen isimlendirmenin sonuna yukarıda örneklerdeki gibi “Handeler” veya “Callback” eklerinin eklenmesi yazılım dünyasında genel kabuldür.

Bir delegate yapısını kullanmak için önce bir delegate tanımlanır. Delegate tanımlaması “Namespace” içinde “Class” dışında olabileceği gibi, “Class” içinde “Method” dışında da tanımlanabilir.

namespace DelegateExample
{
    //NameSpace altında sınıf dışında tanımlanmış “Delegate”
    public delegate string PrintHandler(string message);
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

namespace DelegateExample
{
    class Program
    {
        //Sınıf altında Metod dışında tanımlanmış “Delegate”
        public delegate string PrintHandler(string message);
        static void Main(string[] args)
        {
        }
    }
}

Tanımlanan delegate kullanımı basit bir örnek ile aşağıda açıklanmıştır.

Örnek olarak; konsol penceresine bir yazı yazdırmak için bir metod olsun. Bu metodu şu şekilde çağırabiliriz.

namespace DelegateExample
{
    class Program
    {    
        static void Main(string[] args)
        {
            PrintMessage("Message");
        }
 
        public static void PrintMessage(string mesaj)
        {
            Console.WriteLine(mesaj);
        }
    }
}

Şimdi delegate kullanarak bu metodu çağıralım.

Delegate tanımını oluşturduktan sonra kullanılabilmesi için değişken olarak tanımlanması gereklidir. Bu tanımlama diğer referans veri türleriyle aynı şekildedir.

namespace DelegateExample
{
    class Program
    {
        public delegate void PrintHandler(string param);
        static void Main(string[] args)
        {
            //Delegate'in instance si oluşturuluyor ve 
            //mesaj yazdırma metodu parametre olarak geçiliyor.
            PrintHandler messageHandler = new PrintHandler(PrintMessage);
 
            //Delegate'in işaret ettiği "PrintMessage" 
            //metoduna parametre geçiliyor ve method çağırılıyor.
            messageHandler("Handler'dan çağrılan PrintMessage metodu.");
        }
 
        public static void PrintMessage(string mesaj)
        {
            Console.WriteLine(mesaj);
        }
    }
}

Delegate’in işaret ettiği metodlara aynı parametre geçildiği için her metod aynı mesajı yazdı. Aynı delegate tanımı, farklı methodlar için işlevsel kılınabilir.

namespace DelegateExample
{
    class Program
    {
        public delegate void PrintHandler(string param);
        static void Main(string[] args)
        {
            //Delegate'in instance si oluşturuluyor ve 
            //mesaj yazdırma metodu parametre olarak geçiliyor.
            PrintHandler messageHandler = new PrintHandler(PrintMessage);
 
            //Delegate'in işaret ettiği metodlara
            //parametre geçiliyor ve method çağırılıyor.
            messageHandler("Handler'dan çağrılan PrintMessage.");
 
            //Delegate'e methodun referansı ekleniyor.
            messageHandler = StatusMessage;
 
            //Delegate'in işaret ettiği metodlara
            //parametre geçiliyor ve method çağırılıyor.
            messageHandler("Handler'dan çağrılan StatusMessage.");
        }
 
        public static void PrintMessage(string mesaj)
        {
            Console.WriteLine(mesaj + " - PrintMessage");
        }
 
        public static void StatusMessage(string mesaj)
        {
            Console.WriteLine(mesaj + " - StatusMessage");
        }
    }
}

Bir delegate nesnesi iki şekilde çağrılabilir.

//Direkt nesne üzerinden
messageHandler("Instance");
//Delegate Invoke metodu üzerinden.
messageHandler.Invoke("Invoke Method");

Delegate’e metod eklenebileceği gibi eklenen metodlar da çıkartılabilir.

PrintHandler messageHandler = new PrintHandler(PrintMessage);
//Method ekleme
messageHandler += StatusMessage;
//Metod çıkarma
messageHandler -= PrintMessage;
messageHandler("Message");

Yukarıda “PrintMessage” metodu delegate’den silindi. Sadece “StatusMessage” metodu çağrılacaktır.

Static vs instance atamaları:

Bir delegate değişkenine static bir method verildiğinde, oluşturulan instanceden bağımsız, tüm istanceler ile ortak kullanılır. Static değişkeninin kullanım amacına uygun olarak, beklenildiği gibi, bir değişim görülmez. Aşağıdaki örnekte olduğu gibi. Ancak oluşturulan instanceye bağlı bir method ataması yapılırsa o instanceye göre işlev gösterir.

class Car
{
    //String dönderen delegate
    public delegate string GetHandler();
 
    //Method referanslarini tutacak olan değişkenler
    public GetHandler StaticHandler;
    public GetHandler InstanceHandler;
 
    public string Name { get; set; }
 
    //Static Method
    public static string StaticMethod()
    {
        return "StaticMethod";
    }
 
    //Oluşturulan instancede bulunan Name değeri
    public string GetNameMethod()
    {
        return Name;
    }
}
class Program
{
    public delegate void PrintHandler(string param);
    static void Main(string[] args)
    {
        Car bmw = new Car() { Name = "BMW 320d" };
        Car audi = new Car() { Name = "Audi A8L" };
 
        bmw.InstanceHandler = bmw.GetNameMethod;
        bmw.StaticHandler = Car.StaticMethod;
 
        audi.InstanceHandler = audi.GetNameMethod;
        audi.StaticHandler = Car.StaticMethod;
 
        Console.WriteLine(
            bmw.InstanceHandler() + "\n" +
            audi.InstanceHandler() + "\n" +
 
            bmw.StaticHandler() + "\n" +
            audi.StaticHandler() + "\n"
            );
    }
}
guest
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments
Yusuf Çelik

Güzel içerik

1
0
Düşünceleriniz değerlidir, lütfen yorum yapın.x
()
x