Anonymous Methods (İsimsiz Metodlar) [C#]

2.0’dan önceki C# sürümlerinde bir delegate’i tanımlamak için daha önce tanımlanmış bir metod(named method) kullanmak gerekirdi. C# 2.0 ile birlikte C++’taki inline metodlar gibi isimli metod zorunluluğu ortadan kaldırılmış olup isimsiz metod da kullanılma imkanı sunulmaktadır. Anonymous Method sayesinde bir kod bloğunu, delegate tanımlamasında parametre olarak geçebileceğiz. Delegate çalıştığı zaman kendisine parametre olarak geçilmiş kod bloğunu çalıştırır. Önceki sürümlerden bildiğimiz şekliyle bir delegate tanımlayalım;

button1.Click += new EventHandler(Metod);

void Metod(object sender, System.EventArgs e)
{
    MessageBox.Show("Button tıklandı.");
}//Metod

Bu kod bloğu, anonymous method formatıyla daha sade yazılabilir. Anonymous methodlar, delegate sözcüğüyle başlamak zorundadır.

button1.Click += delegate
{
    MessageBox.Show("Button tıklandı.");
};

Click eventini temsil edecek temsilcinin parametre yapısını da delegate sözcüğünde belirtebiliriz.

button1.Click += delegate(object sender, EventArgs e)
{
    MessageBox.Show(((Button) sender).Name +" isimli button tıklandı.");
};

Eventler için delegate tanımlaması yapılırken önemli rol oynayan bu metodlar, CLR’nın “her kod bloğu mutlaka class’ın metodları içerisinde bulunmalıdır” ilkesinden dolayı CLR tarafından yürütülemezler. Bu yüzden bu kod bloğu, kodlama aşamasında isimsiz görünüyor olsa da derlenme aşamasında, tekil olarak isimlendirilmiş bir metoda dönüştürülür. Örnekteki delegate tanımlamasının MSIL kodunu inceleyelim;

Görüldüğü gibi C# derleyicisi, anonymous methodu örtmek için static bir metod oluşturmuştur.
Aşağıdaki örnekte bir delegate’in hem anonymous metod hem de named metod ile nasıl ilişkilendirildiği gösterilmiştir;

class Program
{
    //Bir delegate tanımlayalım
    delegate void Islem(int X, int Y);

    static void Main()
    {
        //Anonymous method yapısını kullanan delegate
        Islem oIslem = delegate(int A,int B)
        {
            Console.WriteLine("Anonymous method sonucu : "+ (A+B));
        };

        oIslem(10,20);

        //Toplama isimli methodu kullanan delegate
        oIslem = new Islem(Toplama);
        oIslem(15,21);

        Console.ReadLine();
    }//Main

    static void Toplama(int X,int Y)
    {
        Console.WriteLine("Named method(Toplama) sonucu : "+ (X+Y));
    }//Toplama

}//Program

Anonymous method sonucu : 30
Named method(Toplama) sonucu : 36

MSIL kodunu incelediğimizde C# compiler’ın, önceki örnekte olduğu için unique bir metod ismi kullandığını görmüş oluruz.

Bu son örnek, aynı zamanda anonymous methodların herhangi bir türde argüman da kabul ettiklerini göstermektedir. Hatta bu argümanlar, ref ve out sözcükleriyle birlikte de kullanılabilir.

class Program
{
    //Islem isimli delegate tanımlayalım
    delegate int Islem(int valPrm, ref int refPrm, out int outPrm);

    static Islem Yazdir()
    {
        return delegate(int valPrm, ref int refPrm, out int outPrm)
        {
            Console.WriteLine("valPrm parametresinin değeri:{0}", valPrm);
            refPrm++;
            outPrm = 15;
            return valPrm;
        };
    }//Yazdir

    static void Main()
    {
        Islem oIslem = Yazdir();
        int refVar = 7;
        int outVar;
        int x = oIslem(10, ref refVar, out outVar);
        int y = oIslem(20, ref refVar, out outVar);
        Console.WriteLine("x:{0} y:{1} refVar:{2} outVar:{3}", x, y, refVar, outVar);

        Console.ReadLine();
    }//Main

}//Program

valPrm parametresinin değeri:10
valPrm parametresinin değeri:20
x:10 y:20 refVar:9 outVar:15

Metodlara dizi türünde parametre göndermek için kullanılan params sözcüğü, anonymous metodlarında kullanılamaz.
Anonymous metodlarında diğer önemli konu, lokal değişken yönetimidir. Bu metod yapısının, lokal değişkenlerin değerlerini nasıl koruduğunu bir örnek üzerinde inceleyelim;

class Program
{
    //Sayac isimli delegate tanımlayalım
    delegate int DlgSayac();

    static DlgSayac Sayac()
    {
        int counter = 0;
        DlgSayac oSayac = delegate { return ++counter; };
        return oSayac;
    }//Sayac

    static void Main()
    {
        DlgSayac oSayac1 = Sayac();
        DlgSayac oSayac2 = Sayac();

        Console.WriteLine(oSayac1());
        Console.WriteLine(oSayac1());

        Console.WriteLine(oSayac2());
        Console.WriteLine(oSayac2());    

        Console.ReadLine();
    }//Main

}//Program

1
2
1
2

Tanımladığımız delegate’in C# derleyicisi tarafından nasıl bir kod bloğuna çevrildiğini reflector aracılığıyla görelim.

Bu kodlar, bize şunu göstermektedir; Compiler, anonymous metodu normal metod yapısına benzetmek için yalnızca “b__0()” isimli bir metod oluşturmamış buna ek olarak “<>c__DisplayClass1″ isminde bir class oluşturmuştur. Bu class, “b__0()” metodunu çağırmaktadır. Bu metod da anonymous metodun yaptığı işi yapmaktadır. Bu class, aynı zamanda “counter” isminde bir değişken içermektedir. Sağ taraftaki kod bloğundan da anlaşılacağı üzere bu lokal değişkenin değeri, anonymous method tarafından korunmaktadır.
Anonymous metod bloğunu, başka metodlara parametre olarak da gönderebiliriz. Önce basit bir örnek üzerinde gösterelim. Aşağıdaki tabloda rakamlardan oluşan bir dizideki çift sayıların bulunması hem named method hem de anonymous method yöntemiyle gerçekleştirilmiştir.

class Program
{
    static void Main()
    {
        int[] Sayilar = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        int[] CiftSayilar = Array.FindAll(Sayilar, IsCift);

        Console.Write("Çift Sayılar : ");
        foreach (int Sayi in CiftSayilar)
        {
            Console.Write(Sayi +", ");
        }

        Console.ReadLine();
    }

    //Parametre olarak gönderilmiş değerin 2'ye bölünüp bölünmediğini bildirir.
    static bool IsCift(int Sayi)
    {
        return (Sayi % 2 == 0);
    }//IsCift

}//Program
class Program
{
    static void Main()
    {
        int[] Sayilar = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        //Sayının çift olup olmadığını kontrol etmek için yeni bir metod yazılmadı.
        int[] CiftSayilar = Array.FindAll(Sayilar, delegate(int Sayi)
        {
           return (Sayi % 2 == 0);
        });

        Console.Write("Çift Sayılar : ");
        foreach (int Sayi in CiftSayilar)
        {
            Console.Write(Sayi +", ");
        }

        Console.ReadLine();
    }

}//Program

Çift Sayılar : 2, 4, 6, 8, 10,
Konunun daha net anlaşılması için, daha önce generic türler konusunda gördüğümüz dizi elemanlarının sıralamasıyla ilgili bir örnek yapalım.

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List
<code>Yaşa göre sıralama:<br>
---------------------<br>
18 Berna Korkmaz<br>
20 Ali Korkmaz
Ada göre sıralama::<br>
---------------------<br>
20 Ali Korkmaz<br>
18 Berna Korkmaz</code>
Liste içerisindeki elemanları listelerken, .NET 2.0 ile birlikte gelmiş Array.ForEach() metodunu da kullanabiliriz. Bu metodun özelliği, delegate türünde parametre alabiliyor olmasıdır.
foreach (Musteri m in lstMusteri)
{
    Console.WriteLine(m.Yas + " " + m.Adsoyad);
}

satırları yerine aşağıdaki anonymous metod formatı da kullanılabilir.

lstMusteri.ForEach(delegate(Musteri m)
{
    Console.WriteLine(m.Yas + " " + m.Adsoyad);
});

Delegate konusundan hatırlanacağı gibi bir delegate’i “+=” operatörünü kullanarak birden fazla metodla ilişkilendirebiliriz. Bu metodlar aynı şekilde anonymous metod türünde de olabilir. Aşağıdaki örnekte bir delegate, iki tane anonymous metod bir tane de normal metod ile ilişkilendirilmiştir.

class Program
{
    delegate void DelegateTip();

    static void Main()
    {
        DelegateTip oDlg = delegate()
        {
            Console.WriteLine("Metod1");
        };

        oDlg += delegate()
        {
            Console.WriteLine("Metod2");
        };

        oDlg += Metod3;

        //Delegate'i çağıralım
        oDlg();

        Console.ReadLine();
    }//Main

    static void Metod3() {
        Console.WriteLine("Metod3");
    }//Metod3

}//Program

Metod1
Metod2
Metod3

Anonymous Methods (İsimsiz Metodlar) [C#]” üzerine bir düşünce

  1. Ahmet

    verdiğiniz örneklerden birini anlamadım.”lokal değişkenin değerini koruma” için yaptığınız örnek değeri nasıl koruyor anlayamadım. anladığım kadarı ile değer aynı kalmıyor 1-2-1-2 .burada korunan ne .ilgilenirseniz sevinirm. bloğunuz çok faydalı teşekkürler

    Cevapla
  2. Ahmet Kaymaz Yazar

    Ahmet Bey,burada kastettiğimiz şey değişkenin en sonki değerini koruyor olmasıdır.
    İlk başta değişkenin değeri “0¨ idi.
    Console.WriteLine(oSayac1()); -İlk çağrımda 1 oldu
    Console.WriteLine(oSayac1()); -İkinci çağrımda 2 oldu. Yani ilk çağrımdaki “1¨ değerini korumuş oldu. Yeniden “0¨ olmadı. Zaten reflector görüntüsünde görüleceği gibi değişken public olarak tanımlanıyor.

    Cevapla
  3. pcmuh

    Merhabalar, sitenizi inceledim,içerik bakımından benim sitemle benzer içerikte olduğu için hoşuma gitti,Link değişimi düşünürmüsünüz?

    Cevapla

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Time limit is exhausted. Please reload CAPTCHA.