C# 2.0 ve Anonymous (İsimsiz) Metodlar

Değerli Okurlarım Merhabalar,

İsimsiz metodlar bildiğiniz gibi C# 2.0' a eklenmiş olan yeni özelliklerden birisidir. Temeli C# dilinin temsilci tipine dayanan bu yeni teknikte amaç, temsilcileri işaret edecekleri metodların sahip oldukları kod blokları ile bir seferde tanımlayabilmektir. İsimsiz metodları anlayabilmek için herşeyden önce temsilcilerin (delegates) iyi kavranmış olması gerekmektedir(Ön bilgi veya hatırlatma açısından Örnek makale ve video larımızı incelemenizi öneririm)

Kısaca temsilciler, çalışma zamanında metodların başlangıç adreslerini işaret eden tip (type) lerdir. Temsilcilerin herhangibir metodu çalışma zamanında işaret edebilmesinin yanı sıra bu metodu(metodları) çağırlabilmesi ve hatta parametreler göndererek dönüş değerleri vermesi gibi yetenekleride vardır. Ama tüm bu özellikleri arasında en önemlisi, çalışma zamanında hangi metodu çalıştıracağına karar vermesidir.

Temsilciler (delegates), multithreading(çok kanallı programlama) modelinde, event-driven (olay güdümlü) programlamada, CallBack Modeli ile Asenkron erişim tekniklerinde etkin olarak kullanılmaktadır.


C# 2.0 ile gelen isimsiz (anonymous) metodları anlamak için öncelikle C# dilinde bir temsilciyi nasıl kullandığımıza bakmamızda fayda var. Aşağıdaki örnekte basit olarak bir temsilci tanımlanmış ve kullanılmıştır. Bu temsilci iki adet double tipte parametre alan ve geriye double tipinden değerler döndüren metodları işaret edebilecek şekilde tanımlanmıştır. Dikkat ederseniz temsilci nesnemize ait nesne örneğimiz oluşturulurken işaret edeceği metod parametre olarak verilmektedir. Daha sonra bu temsilci nesne örneği üzerinden işaret edilen metod çağırılabilmektedir.

using System;

namespace DefiningDelegate
{ 
    //Temsilcimiz iki adet double tipinden parametre alan ve geriye double tipinden değer döndüren metodları işaret edebilecek.
    public delegate double Temsilci(double pi,double r);

    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            // Temsilci nesnemiz oluşturuluyor ve Alan isimli metodu işaret edeceği söyleniyor.
            Temsilci t=new Temsilci(Alan);
            // Temsilcimizin çalışma zamanında işaret ettiği metod çağırılıyor.
            double daire_Alani=t(3.14,10);
            Console.WriteLine(daire_Alani);
        }
    
        // Tanımladığımız temsilci tarafından işaret edilebilecek formatta bir metod bildirimi.
        static double Alan(double pi_Degeri,double yaricap)
        {
            return pi_Degeri*(yaricap*yaricap);
        }
    }
}

C# 2.0 için anonymous metodları kullanarak yukarıdaki uygulamayı aşağıdaki kod parçasında görüldüğü gibi yazabiliriz. Yeni versiyonda temsilci kullanımındaki tek fark temsilcinin işaret edeceği metod bloğunun, çalışma zamanında bu metodu çağıracak olan temsilci nesnesine eklenmiş oluşudur. Buradan temsilcilerin inline (satır içi) kodlama yeteneği kazanmış olduklarını söyleyebiliriz.

İsimsiz(Anonymous) metodlar dışarıdan parametre alabilirler ve geriye değer döndürebiliriler.


C# 2.0 versiyonu

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingAnonymousMethods
{ 
    // Temsilcimizi tanımlıyoruz.
    public delegate double Temsilci(double a,double b);

    class Program
    {    
        static void Main(string[] args)
        {
            // Temsilcimizi hem oluşturuyor hemde işaret edeceği metod bloğunu anonymous olarak tanımlıyoruz.
            Temsilci t = delegate(double pi,double r) 
            {
                return pi * r*r;
            };
            // Temsilcimizi parametreler ile birlikte çağırıyoruz ve dönüş değerini double tipinden bir değişkene atıyoruz.
            double alan = t(3.14, 10);
            Console.WriteLine(alan);
        }
    }
}

Gelelim isimsiz metodların bir diğer kullanım şekline. Çok kanallı (Multithreading) programlama modelinde bildiğiniz gibi ThreadStart isimli bir temsilci(delegate) tipi kullanılmaktadır. Bu temsilci bir Thread nesne örneğinin oluşturulması sırasında, yapıcı metod için parametre olarak kullanılmaktadır. C# 1.1 versiyonunda basit bir thread modeli aşağıdaki kod parçasında olduğu gibi örneklenebilir. Lütfen temsilcilerin çalışma zamanında işaret edecekleri metodlar ile birlikte nasıl ilişkilendirildiğine dikkat edin.

using System;
using System.Threading;

namespace UsingThreading1
{
    class Class1
    {
        //ThreadStart temsilcimiz çalışma zamanında ilgili process içindeki metodu temsil edecek.
        static ThreadStart threadStart1;
        static ThreadStart threadStart2;

        // Thread nesnemiz parametre olarak aldığı ThreadStart temsilcisinin işaret ettiğim metodun ait olduğu process için gerekli işlemleri (start,abort,resume vb...) gerçekleştirecek. 
        static Thread thread1;
        static Thread thread2;

        // Thread içinde çalışacak metodlarımız.
        static void Say1()
        {
            for(int i=0;i<100;i++)
            {
                Console.Write(i);
                Thread.Sleep(100);
            }
        }

        static void Say2()
        {
            for(int i=0;i<100;i++)
            {
                Console.WriteLine(i);
                Thread.Sleep(150);
            }
        }

        [STAThread]
        static void Main(string[] args)
        {
            // ThreadStart temsilcilerimiz çalışma zamanında işaret edecekleri parametre olarak alacak         şekilde tanımlanıyor.
            threadStart1=new ThreadStart(Say1);
            threadStart2=new ThreadStart(Say2);
            // Thread nesnelerimiz ThreadStart temsilcilerinin parametre olarak alacak şekilde tanımlanıyor.
            thread1=new Thread(threadStart1); 
            thread2=new Thread(threadStart2);
            // Threadler çalıştırılmaya başlanıyor.
            thread1.Start();
            thread2.Start();
        }
    }
}

Şimdi aynı örneğin C# 2.0' da isimsiz metodlar yardımıyla nasıl yazılabileceğine bakalım. Burada dikkat ederseniz ThreadStart temsilcisi görülmemektedir. Bu elbetteki ThreadStart temsilcisinin kullanılmadığı anlamına gelmemelidir. Aslında bu tanımlama gizli olarak Thread sınıfına ait nesne örnekleri oluşturulurken yapılmaktadır. Yani çalışma zamanında Thread nesnesinin zaten bir ThreadStart temsilci nesnesine ihtiyacı olduğu çalışma ortamı tarafından bilinmektedir. Diğer yandan kod yazımı açısından bakıldığında iki işlemin, (ThreadStart' ın işaret edeceği metodu gösterecek şekilde örneklenmesi ve daha sonrada Thread nesnesinin oluşuturulması için parametre olarak kullanılması) tek seferde yapılmaktadır.

C# 2.0 Versiyonu

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace UsingAnonymousMethods
{ 
    class Program
    {
        // Thread içerisinde çalışacak metodumuz.
        static void Say1()
        {
            for(int i=0;i<100;i++)
            {
                Console.Write(i);
                Thread.Sleep(100);
            }
        }

        static void Main(string[] args)
        {
            // İlk Thread nesnemizi örneklerken ThreadStart temsilcisinin işaret edeceği metodu burada anonymous metod olarak tanımlıyoruz.
            Thread thread1=new Thread(delegate(){
                Say1();
            });
            // Tanımladığımız thread' i çalıştırıyoruz.
            thread1.Start();
            // İkinci Thread nesne örneğimizi oluşturuyoruz. Bu sefer thread1 nesnesinden farklı olarak anonymous metodumuz içerisine direkt kodları gömdük. thread1 nesnesinde ise kodları içeren metodu, anonymous metod bloğumuz içine gömmüştük.
            Thread thread2 = new Thread(delegate(){
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine(i);
                    Thread.Sleep(150);
                }
            });
            thread2.Start();
        }
    }
}

Temsilcilerin kullanıldığı diğer bir tekniğinde olay güdümlü (event-driven) programlama modeli olduğunu söylemiştik. Bu modelde de Threading modeline benzer bir yapı vardır. Her event (olay) tanımlanırken bir temsilci kullanılır. Bu temsilci olay meydana geldiğinde çalıştırılacak olan metodu çalışma zamanında işaret etmek ve çağırmakla yükümlüdür. Örneğin aşağıdaki kod parçasında  bir windows formu üzerinde yer alan button kontrolünün Click olayına ilişkin kodlar yer almaktadır.

Bu örneğimizde, dikkat ederseniz button kontrolümüze Click event' ını yükleyebilmek için System.EventHandler temsilci tipi kullanılmaktadır. Bu temsilci, diğer olay metodlarında kullanılan temsilciler gibi sistemde önceden tanımlanmış halde yer almaktadır. InitializeComponent metodunda button kontrolümüze click olayı yüklenirken, hangi temsilcinin çalışma zamanın hangi metodu işaret edeceği ve çalıştıracağıda bildirilir. Sonrasında ise bu olay metodunun tanımlanması gerekmektedir.

public class Form1 : System.Windows.Forms.Form
{
    private System.Windows.Forms.Button btnAksiyon; 
    
   
    // Diğer kodlar
    
    private void InitializeComponent()
    {
        
        
        // Diğer Kodlar
        
        this.btnAksiyon.Click += new System.EventHandler(this.btnAksiyon_Click);
    }
    
    
    // Diğer Kodlar
    
    private void btnAksiyon_Click(object sender, System.EventArgs e)
    {
        // Bir takım kodlar.
    }
}

Şimdi aynı örneğin C# 2.0' da isimsiz metodlar yardımıyla nasıl yazılabileceğine bakalım. Görüldüğü gibi System.EventHandler temsilcisi burada görülmemektedir. Aslında tüm isimsiz metod modellerinde, temsilcilerden hangisi kullanılırsa kullanılsın (örneğin System.EventHandler veya ThreadStart gibi) bizim tek kullandığımız delegate anahtar sözcüğü ile bir metod bloğunun kombinasyonudur. Bu isimsiz metodların kullanımının bir faydası olarakta görülebilir.

İsimsiz(Anonymous) metodlarda, kullanılan temsilcinin bilinmesine gerek yoktur. delegate anahtar sözcüğü bu işi üstlenir.


C# 2.0 Versiyonu

private void InitializeComponent()
{
    
    // Diğer kodlar
    
    this.btnOnay.Click += delegate(object sender, System.EventArgs arg)
    {
        System.Windows.Forms.MessageBox.Show("Onay");
    };    
    
    // Diğer kodlar
    
}

İsimsiz metodlar uygulanışları açısından biraz karışık görülebilir. En azından alışıncaya kadar. Ancak kavrandıklarında çok faydalı olduklarını söyleyebiliriz. Nitekim temsilci nesnelerimizin tanımlaması gereken yerlerde direkt olarak kod bloklarını kullanmak oldukça kullanışlı bir teknik olarak karşımıza çıkmaktadır. Bu makalemizde C# 2.0 ile birlikte gelen isimsiz metod kavarmını, her zaman için içiçe olduğu temsilciler ile birlikte incelemeye çalıştık. Bir sonraki makalemizde görüşünceye dek hepinize mutlu günler dilerim.

Yorum ekle

Loading