Delegate etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Delegate etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

C# Lambda Expressions Kullanımı

C# Anonymous Methods (İsimsiz Metodlar) Kullanımı yazımızda isimsiz metodların kullanımından bahsetmiştik. Aslında Lambda Expressions isimsiz metod yaratmanın kısa yoludur.

Lambda Expressions'ı generic List<T> sınıfının FindAll() metodu üzerinden incelemeye çalışalım.
 
     // Method of the System.Collections.Generic.List<T> class.
     public List<T> FindAll(Predicate<T> match)

Yukarıda FindAll metodunun freamwork içerisindeki tanımlamasını görüyorsunuz. Gördüğünüz gibi FindAll Predicate<T> delegelesini parametre alıyor. Predicate<T> delegesi bool döndüren ve bir parametre alan metodları saklayan generic bir parametredir. Freamwork içerisindeki tanımı şu şekildedir:

    // This delegate is used by FindAll() method
    // to extract out the subset.
    public delegate bool Predicate<T>(T obj);

FindAll metodunu çalıştırdığımızda listemizin içerisindeki elemanlar sırasıyla Predicate<T> delegesinin tuttuğu metodlara gidecek ve geriye true yada false değeri dönecektir.

Önce klasik delege tanımı ile bir liste içerisindeki çift sayıları bulan programımızı yazalım:

    class Program
    {
        static void Main(string[] args)
        {
            TraditionalDelegateSyntax();
        }

        static void TraditionalDelegateSyntax()
        {
            List<int> numbers = new List<int>();
            numbers.AddRange(new int[] { 5, 7, 9, 14, 17, 2, 6 });

            //klasik delege tanimi ile
            Predicate<int> predicate = new Predicate<int>(IsEvenNumber);
            List<int> evenNumbers = numbers.FindAll(predicate);

            foreach (int item in evenNumbers)
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

        // Target for the Predicate<> delegate.
        static bool IsEvenNumber(int i)
        {
            // Is it an even number?
            return (i % 2) == 0;
        }
    }

Gördüğünüz gibi önce Predicate<int> tipinde bir delege nesnesi tanımladık. Ardından IsEvenNumber metodunu bu delegenin saklayacağı metod olarak parametre verdik. Ardından FindAll metodu ile bu delegenin taşıdığı IsEvenNumber metodunu number listemizin her adımı için çalıştırdık. Klasik yöntem ile bu şekilde FindAll metodunu çalıştırabiliriz. Şimdi birde aynı örneği Anonymous Methods ile yazalım:

        static void AnonymousMethodsDelegateSyntax()
        {
            List<int> numbers = new List<int>();
            numbers.AddRange(new int[] { 5, 7, 9, 14, 17, 2, 6 });

            //Anonymous Methods ile
            List<int> evenNumbers = numbers.FindAll(
                delegate(int i){ return (i % 2) == 0; }
                );

            foreach (int item in evenNumbers)
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

Bu şekilde isimsiz metodlar ile çift sayı bulma işlemini gerçekleştirmiş olduk. İsimsiz metodlar ile ilgili detaylı bilgiye şu yazıdan ulaşabilirsiniz: C# Anonymous Methods (İsimsiz Metodlar) Kullanımı 

Son olarak Lambda Expressions ile yazımına bakalım:

        static void LambdaExpressionsSyntax()
        {
            List<int> numbers = new List<int>();
            numbers.AddRange(new int[] { 5, 7, 9, 14, 17, 2, 6 });

            //Lambda Expressions ile
            List<int> evenNumbers = numbers.FindAll(i => i % 2 == 0);

            foreach (int item in evenNumbers)
            {
                Console.WriteLine(item);
            }

            Console.ReadLine();
        }

Gördüğünüz gibi Lambda Expressions ile yazımı çok basit bir hale geldik. Compiler Lambda Expressions gördüğünde o satırı Anonymous Methods'a çevirir ve öyle yorumlar. Örneğin yukarıdaki örneği ildasm exe ile açarsanız Lambda Expressions içeren satırının Anonymous Methods'a çevrildiğini görürsünüz:

      List<int> evenNumbers = list.FindAll(delegate (int i)
      {
          return (i % 2) == 0;
      });

Lambda Expressions ile yazdığımız kod şu an sadece return işlemi yapıyor. Fakat biz birden fazla işlemi burada yaptırabiliriz:

      List<int> evenNumbers = list.FindAll((i) =>
      {
          Console.WriteLine("value of i is currently: {0}", i);
          bool isEven = ((i % 2) == 0);
          return isEven;
      });

Eğer hiç bir parametre gönderilmiyor ise metoda şu şekilde Lambda Expressions yazılır:

       VerySimpleDelegate d = new VerySimpleDelegate( 
       () => {return "Enjoy your string!";} );

Eğer birden fazla parametre gönderiliyor ise:

       VerySimpleDelegate d = new VerySimpleDelegate( 
       (msg, result) => 
         {Console.WriteLine("Message: {0}, Result: {1}", msg, result);} );

Çıktı:



Örnek Proje:

LambdaExpressionsExample.rar

C# Anonymous Methods (İsimsiz Metodlar) Kullanımı

Önceki C# Delegate Kullanımı I - Delege Nedir? ve C# Delegate Kullanımı II - Generic Delegeler yazılarımızda delege kavramından bahsetmiştik. Bu yazılarımızda delege tanımlarını daha önce tanımlanmış olduğumuz named metodlar ile yaptık. C# 2.0 ile birlikte bunu isimsiz metodlar ile yapabiliyor hale geldik.

button1.Click += delegate
{
    MessageBox.Show("isimsiz metodumuz calisti");
};

Önce daha önceki yazılarımızda named metodlar ile yazdığımız delege örneğimizi hatırlayalım:

    public class Person
    {
        public delegate void PersonChangeHandler(Person person
                    , string fieldName, string newValue);
        public event PersonChangeHandler PersonHasChanged;

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if (PersonHasChanged != null)
                    PersonHasChanged(this, "Name", value);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };
            p1.PersonHasChanged += ShowChangedUser;
            p1.PersonHasChanged += SendChangedUserInformation;
            p1.Name = "Test";

            Console.ReadLine();

        }

        static void ShowChangedUser(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Field: {1} 
                    New Value: {2}", p.PersonId, fieldName, newValue);
        }

        static void SendChangedUserInformation(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Bilgilendirme maili 
                    gonderiliyor", p.PersonId, fieldName, newValue);
        }
    }

Şimdi bunu anonymous methodlar ile nasıl yaparız ona bakalım:

    public class Person
    {
        public delegate void PersonChangeHandler(Person person
                    , string fieldName, string newValue);
        public event PersonChangeHandler PersonHasChanged;

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if (PersonHasChanged != null)
                    PersonHasChanged(this, "Name", value);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };

            //ÖNEMLİ!! ShowChangedUser yerine isimsiz metod kullandik
            p1.PersonHasChanged += delegate(Person p, string fieldName
            , string newValue)
            {
                Console.WriteLine(@"Person ID: {0} Field: {1}   
                    New Value: {2}", p.PersonId, fieldName, newValue);
            };

            //ÖNEMLİ!! SendChangedUserInformation yerine isimsiz metod kullandik
            p1.PersonHasChanged += delegate(Person p, string fieldName
            , string newValue)
            {
                Console.WriteLine(@"Person ID: {0} Bilgilendirme maili   
                    gonderiliyor", p.PersonId, fieldName, newValue);
            };

            //ÖNEMLİ!! parametresiz isimsiz metodda kullanabiliriz
            p1.PersonHasChanged += delegate
            {
                Console.WriteLine("Degisiklik calisti.");
            };

            p1.Name = "Test";

            Console.ReadLine();

        }
    }

Gördüğünüz gibi artık ShowChangedUser ve  SendChangedUserInformation named metodlarını kullanmadık onun yerine isimsiz metodlar ile delege tanımlarımızı gerçekleştirdik.

Burda önemli noktalardan biri en son metod atama işleminde parametresiz metod ataması yapabildik. Named metod kullansaydık buna izin verilmiyor olurdu. Çünkü named metod kullanımında metodun parametreleri ile delege tanımındaki parametrelerin uyuşması gerekmektedir.

Çıktı:




İsimsiz metodlar kod aşamasında isimsiz gözüksede derlenme aşamasında, unique olarak isimlendirilmiş bir metoda dönüştürülür. ildasm ile yazdığınız koda bakarsanız bunu açıkça görebilirsiniz.

Anonymous Methodlar:

* Anonymous methodlar, delegate sözcüğüyle başlamak zorundadır.
* Herhangi bir türde parametre kabul ettiklerini ederler. ref ve out sözcükleriyle birlikte de kullanılabilir.
* params sözcüğü, anonymous metodlarda kullanılamaz.
* Tanımlandığı sınıf içerisindeki herhangi bir değişken ile aynı isme sahip değişkeni olamaz.
* Bir metoda parametre olarak gönderilebilir. Örnek:

        int[] CiftSayilar = Array.FindAll(Sayilar, delegate(int Sayi)
        {
           return (Sayi % 2 == 0);
        });

Örnek Proje:
AnonymousMethodsExample.rar

C# Event Kullanımı II - Generic Events

C# Event Kullanımı yazımızda event kavramına giriş yapmıştık. Bu yazımızda generic event kavramını incelemeye çalışacağız.

EventArgs sınıfından türeyen kendi custon EventArgs sınıfımızı yazabiliriz:

    public class CustomEventArgs : EventArgs
    {
        public int PersonId { get; set; }
        public string FieldName { get; set; }
        public string NewValue { get; set; }
    }


CustomEventArgs sınıfımızı yazdıktan sonra artık delege tanımı yapmadan freamwork içerisinde event handle etmek için kullanılan EventHandle<> generic sınıfını kullanarak programımızı yazabiliriz.

    class Person
    {
        public event EventHandler<CustomEventArgs> PersonHasChanged;

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if (PersonHasChanged != null)
                {
                    CustomEventArgs c = new CustomEventArgs();
                    c.PersonId = this.PersonId;
                    c.FieldName = "Name";
                    c.NewValue = value;
                    PersonHasChanged(this, c);
                }
            }
        }

    }
    public class CustomEventArgs : EventArgs
    {
        public int PersonId { get; set; }
        public string FieldName { get; set; }
        public string NewValue { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };
            p1.PersonHasChanged += ShowChangedUser;
            p1.PersonHasChanged += SendChangedUserInformation;
            p1.Name = "Test";

            Console.ReadLine();

        }

        static void ShowChangedUser(object sender, CustomEventArgs e)
        {
            Console.WriteLine(@"Person ID: {0} Field: {1} 
                    New Value: {2}", e.PersonId, e.FieldName, e.NewValue);
        }

        static void SendChangedUserInformation(object sender
                , CustomEventArgs e)
        {
            Console.WriteLine(@"Person ID: {0} Bilgilendirme maili 
                    gonderiliyor", e.PersonId, e.FieldName, e.NewValue);
        }
    }

Çıktı:


C# Event Kullanımı I - Event Nedir?

Önceki C# Delegate Kullanımı I - Delege Nedir? ve C# Delegate Kullanımı II - Generic Delegeler yazılarımızda delege kavramından bahsetmiştik. Kısacası delegeleri metot saklamak için kullandığımızı hatırlayalım.

Bu yazıları okuduysanız ya da delegeler hakkında bilginiz var ise programlarımızda delege kullanacaksak bir çok tanımlama yapmamız gerekiyor: delege tanımlama, encapsule için custom register ve unregister metotları gibi.

Şimdi düşünelim ki Person isminde bir sınıfımız var ve biz Person nesnesi üzerinde bir değişiklik yapılınca bir takım metodların çalışmasını istiyoruz. Bu durumda şöyle bir tasarım gerçekleştirebiliriz: bir delege tanımlarız ardından bu delegenin tutacağı metodları setlemek için bir metod yazarız ve bu sayede bir değişiklik olduğunda istediğimiz metodların çalışmasını sağlarız. Gördüğünüz gibi event kullanmadan tasarımı gerçekleştirdik. Şimdi bunu koda dökelim:

    public class Person
    {
        public delegate void PersonChangeHandler(Person person
           , string fieldName
           , string newValue);
        private PersonChangeHandler PersonHasChanged;

        public void RegisterMethod(PersonChangeHandler methodToAdd)
        {
            PersonHasChanged += methodToAdd;
        }

        public void UnregisterRegisterMethod(PersonChangeHandler methodToAdd)
        {
            PersonHasChanged -= methodToAdd;
        }

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if(PersonHasChanged != null)
                    PersonHasChanged(this, "Name", value);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };
            p1.RegisterMethods(ShowChangedUser);
            p1.RegisterMethods(SendChangedUserInformation);
            p1.Name = "Test";

            Console.ReadLine();
        }

        static void ShowChangedUser(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"\nPerson ID: {0} Field: {1} 
                    New Value: {2}", p.PersonId, fieldName, newValue);
        }

        static void SendChangedUserInformation(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Bilgilendirme maili 
                    gonderiliyor", p.PersonId, fieldName, newValue);
        }
    }

Çıktı:



Gördüğünüz gibi PersonChangeHandler isminde bir delege tanımladık. Daha sonra Person sınıfımızın içerisine PersonHasChanged isminde delege nesne örneği tanımladık. Ardından custom register ve unregister metodlarımızı yazdık. Burada PersonHasChanged delege nesne örneğinin private tanımlanması önemli çünkü bununla encapsule işlemini gerçekleştirmiş olduk. Client delege nesne örneğine direk ulaşamıyor ancak register ve unregister metodları ile delegeye yeni metodlar ekleyip çıkarabiliyor.

Peki PersonHasChanged public olsaydı ne olurdu? Bu durumda artık custom register ve unregister metodları yazmamıza gerek kalmazdı. Yeni programımız şu şekilde olurdu:

    public class Person
    {
        public delegate void PersonChangeHandler(Person person
           , string fieldName
           , string newValue);
        public PersonChangeHandler PersonHasChanged;

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if(PersonHasChanged != null)
                    PersonHasChanged(this, "Name", value);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };
            p1.PersonHasChanged += ShowChangedUser;
            p1.PersonHasChanged += SendChangedUserInformation;
            p1.Name = "Test";

            Console.ReadLine();
        }

        static void ShowChangedUser(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"\nPerson ID: {0} Field: {1} 
                    New Value: {2}", p.PersonId, fieldName, newValue);
        }

        static void SendChangedUserInformation(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Bilgilendirme maili 
                    gonderiliyor", p.PersonId, fieldName, newValue);
        }
    }

Bu şekilde de programımız çalışacak ve aynı sonucu üretecektir. Fakat burada bir sorun var. Encapsule işlemi gerçekleştirmedik. Client direk olarak delege nesnesine ulaşabiliyor. Bu sayede artık clientin istediği gibi delegenin Invoke metodunu çalıştırma özgürlüğü var. Örneğin aşağıdaki kodu artık yazabilir:

            p1.PersonHasChanged.Invoke(p1, "hebele", "hübele");

Bu durumda çıktı:



Gördüğünüz gibi client gitti p1 nesnemizin sanki hebele diye bir alanı varmış gibi bunun değiştiğini belirtti ve metodların çalışmasına neden oldu. Bu önemli bir güvenlik açığı oldu programımız için. Peki ne yapabiliriz?

Event kavramı tam burada ihtiyacımıza koşuyor. Eventlar, delegelerin encapsule edilmiş halidir. PersonHasChanged delege örneğini event olarak tanımlasaydık hem custom register ve unregister metodlarını yazmaktan kurtulurduk hem de yukarıda anlattığımız public encapsule problemini yaşamazdık.

Şimdi programımızı birde event ile yazalım:

public class Person
    {
        public delegate void PersonChangeHandler(Person person
                    , string fieldName, string newValue);
        public event PersonChangeHandler PersonHasChanged;

        public int PersonId { get; set; }
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                //eger method set edildi ise
                if (PersonHasChanged != null)
                    PersonHasChanged(this, "Name", value);
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person() { PersonId = 1, Name = "Safak" };
            p1.PersonHasChanged += ShowChangedUser;
            p1.PersonHasChanged += SendChangedUserInformation;
            p1.Name = "Test";

            Console.ReadLine();

        }

        static void ShowChangedUser(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Field: {1} 
                    New Value: {2}", p.PersonId, fieldName, newValue);
        }

        static void SendChangedUserInformation(Person p, string fieldName
            , string newValue)
        {
            Console.WriteLine(@"Person ID: {0} Bilgilendirme maili 
                    gonderiliyor", p.PersonId, fieldName, newValue);
        }
    }

Gördüğünüz gibi hem custom register ve unregister işlemlerinden kurtulduk hem de bu sayede event ile delegemiz encapsule olduğu için client Invoke metodunu kafasına göre çalıştıramadı.

p1.PersonHasChanged'ın sonuna nokta koyup metot listesine erişmeye çalışırsanız hiç bir metodun çıkmadığını görürsünüz.

C# windows form uygulaması geliştirdiyseniz burada eventların bolca kullanıldığını görürsünüz. Buton click event'ı gibi bir çok event bulunmakta. Konuyu daha iyi anlamak için bu eventları incelemenizi öneririm.

Örnek Projeler:
PublicDelegateProblem.rar
EventDelegateExample.rar




C# Delegate Kullanımı II - Generic Delegeler

C# Delegate Kullanımı I - Delege Nedir? yazımızda delege kavramını, ne işe yaradığını, nerelerde kullanıldığını incelemiştik.

C# generic delege tanımlama yapmamıza olanak sağlar. Örneğin, void döndüren ve bir parametre alan 2 metodumuz olsun: StringTarget; string tipinde parametre alıyor ve geriye void döndürüyor. IntTarget ise int tipinde parametre alıyor ve o da geriye void döndürüyor.

Normal şartlarda 2 delege tanımlamamız birine string parametresi diğerine int parametresi yazmamız gerekir. Şimdi ilk aklımıza gelen şekilde bu programı yazalım:

        delegate void MyStringDelegate(string args);
        delegate void MyIntDelegate(int args);

        static void Main(string[] args)
        {
            MyStringDelegate stringDelegate = new MyStringDelegate(StringTarget);
            MyIntDelegate intDelegate = new MyIntDelegate(IntTarget);

            stringDelegate("Safak");
            intDelegate(26);

            Console.ReadLine();
        }

        static void StringTarget(string arg)
        {
            Console.WriteLine("arg in uppercase is: {0}", arg.ToUpper());
        }
        static void IntTarget(int arg)
        {
            Console.WriteLine("++arg is: {0}", ++arg);
        }

Gördüğünüz gibi string tipinde parametre alan metodumuz için MyStringDelegate, int tipinde parametre alan metodumuz için ise MyIntDelegate delegesini tanımladık. Peki yine void döndüren fakat parametre olarak double alan bir metodu delege etmek istesek ne yapacağız? Bu durumda yeni bir MyDoubleDelegate yazmamız gerekecek. Bu durumu ortadan kaldırmak için şimdi bu programı birde generic delege kullanarak yazalım:

 
        //generic delegate
        delegate void MyGenericDelegate<T>(T args);

        static void Main(string[] args)
        {
            //generic delegate
            MyGenericDelegate<string> stringDelegate 
                = new MyGenericDelegate<string>(StringTarget);
            MyGenericDelegate<int> intDelegate 
                = new MyGenericDelegate<int>(IntTarget);

            stringDelegate("Safak");
            intDelegate(26);

            Console.ReadLine();
        }

        static void StringTarget(string arg)
        {
            Console.WriteLine("arg in uppercase is: {0}", arg.ToUpper());
        }
        static void IntTarget(int arg)
        {
            Console.WriteLine("++arg is: {0}", ++arg);
        }

Gördüğünüz gibi delegate void MyGenericDelegate<T>(T args); generic delege tanımı yaparak Hem StringTarget hemde IntTarget metodlarını saklayabildik. Bundan sonra double paramere alan geriye void döndüren bir fonksiyon yazsakta yeni bir delege tanımı yapmamıza gerek kalmayacak, MyGenericDelegate üzerinden nesne örneği oluşturup T yerine double vererek bunu gerçekleştirebiliriz.

Çıktı:



Action<> ve Func<> Kullanımı:

Normal şartlarda delege kullanmamız için şu adımları gerçekleştirmemiz gerekiyor:
* İçinde saklayacağı metot formatına uygun custom delege tanımı yapmak
* Bu custom delegeden bir nesne örneği oluşturmak
* Oluşturduğumuz nesne üzerinden Invoke işlemini gerçekleştirmek
Action<> ve Func<> kısa bir şekilde delege tanımı yapmamıza olanak sağlıyor.

Action<> Kullanımı:

Geriye void döndüren metodları tutan delegeleri kısa yoldan tanımlamamızı sağlar.

        static void Main(string[] args)
        {
            Action<string, int> action
                      = new Action<string, int>(DisplayAge);
            action("Safak", 26);
        }

        static void DisplayAge(string fullName, int age)
        {
            Console.WriteLine(fullName + " : " + age);
        }

Gördüğünüz gibi delege tanımı yapmadan DisplayAge metodu saklandı ve Invoke edilebildi. Bir kez daha söylemekte fayda var Action<> geri değer döndürmez.

Func<> Kullanımı:

Action<> 'ın geri değer döndürebilen halidir. Son parametre dönüş değer tipini belirtir. Örnek kullanım:

        static void Main(string[] args)
        {
            Func<DateTime, double> func 
                 = new Func<DateTime, double>(GetUserAgeAtTime);
            double dateDif = func(DateTime.Now.AddYears(-2));
            Console.WriteLine("\nDate Dif: {0}", dateDif);

            Console.ReadLine();
        }

        static double GetUserAgeAtTime(DateTime birthDate)
        {
            return (DateTime.Now - birthDate).TotalDays;
        }

Yukarıdaki örnekte <DateTime, double> şeklinde yazılmıştır. DateTime parametrenin tipini double ise dönüş değer tipini belirtir.

Örnek ProjelerGenericDelegateExample.rar ,  ActionFuncExample.rar

C# Delegate Kullanımı I - Delege Nedir?

C# dilinde delegelerin kullanım amacı metot saklamaktır. Delegeler Olay(event) tabanlı programlama ve asenkron programlama yaparken, anonim metot yazarken kullanılır. Bir diğer kullanım amacı da, bir metoda parametre olarak başka bir metot verebilmektir.

Delegate tanımlanırken şu öğeler belirtilmelidir:
* Saklanacak metot
* Eğer dönüş değeri varsa dönüş değeri
* Eğer saklanacak metodun parametreleri varsa bu parametreler

Örnek bir delege tanımı:

    delegate int MyDelegate(int x);
    MyDelegate temsilci = new MyDelegate(CalisacakMetot);

Yukarıda örnek bir delege tanımı yaptık. İlk satırda yazdığımız "delegate int" delege içerisinde saklayacağımız metodun int tipinde dönüş değeri olacağını gösteriyor. "(int x)" ise saklayacağımız metodumuzun int tipinde değer alacağını gösteriyor. Alt satıra geçersek ise "CalisacakMetot" delegemizin saklayacağı metot ismidir. Kısacası bu delege tanımı; programımızın içinde şu şekilde tanımladığımız "int CalisacakMetot(int x)" metodunu gerektiğinde çağırmak için saklıyor.

Şimdi örnek bir delege uygulaması yapalım:

    delegate int MathOperation(int x, int y);

    public class SimpleMath
    {
        public static int Add(int x, int y)
        { 
            int retVal = x +y;
            Console.WriteLine("Add : " + retVal);
            return retVal;
        }
        public static int Subtract(int x, int y)
        {
            int retVal = x - y;
            Console.WriteLine("Subtract : " + retVal);
            return retVal;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MathOperation mathOp = new MathOperation(SimpleMath.Add);
            mathOp(5,3);

            Console.ReadKey();
        }
    }

Burada "delegate int MathOperation(int x, int y);" satırıyla basit bir delege tanımı yaptık. Tanımı yaparken saklayacağı metodların dönüş tiplerinin int olması gerektiğini ve bu metodların int tipinde 2 parametre alması gerektiğini belirttik.

Daha sonra ise "MathOperation mathOp = new MathOperation(SimpleMath.Add)" bu satır ile mathOp delege nesnesi oluşturduk. Nesne örneği oluşturulurken construtor üzerinden bu delege nesnesine SimpleMath.Add metodunu saklaması için ekledik. Artık delegemiz bu metodu saklar hale geldi.

En canalıcı kısma geçersekte "mathOp(5,3)" bu şekilde delege nesnemiz üzerinden sakladığı metot olan SimpleMath.Add metoduna 5 ve 3 değerlerini verip bu metodu çalıştırdık.

Program çalıştığında çıktı 5+3'ten "Add : 8" şeklinde olacaktır.

Çıktı:



Bir delege birden fazla metot saklayabilir. "+=" ile delegeye metot ekleyebiliriz. Eklediğimiz metodlar FIFO mantığıyla ilk eklenen metoddan başlayıp sen eklenen metoda doğru sırayla çalıştırılır.

    mathOp += SimpleMath.Subtract;

programımıza bu satırı eklediğimizde artık önce Add metodu ardından Subtract metodu çalışacaktır. Şimdi çıktımız şu şekilde olacaktır.



Metod ekleyebildiğimiz gibi "-=" ile saklanan metodları silebilirizde:

    mathOp -= SimpleMath.Add;

Bu kod satırının ardından artık Add metodu çalışmıyacaktır. Çıktı artık şu şekilde olcaktır:



Bir delege tanımı yapılınca arka planda System.MulticastDelegate'den türetilmiş sealed bir class oluşturulur.

ildasm toolu ile exe'mizin içerisine bakarsanız bizim MathOperation delegemizin için de sealed bir class oluşturulmuş olduğunu görürsünüz.



Burada dikkatinizi BeginInvode, EndInvoke ve Invoke metodlarına çekmek istiyorum.

Invoke: Saklanan metodları senkron şekilde çalıştırır. Örneğimize dönersek "mathOp(5,3)" dediğimizde aslında "mathOp.Invoke(5,3)" metodu çalışıyor ve saklanan metodlarımız Invoke metodu yardımıyla sırayla çalıştırılıyor.

BeginInvoke ve EndInvoke ise asenkron işlemlerde kullanılıyor fakat bu konuya ileriki yazılarımızda incelemeye çalışacağız.

GetInvocationList: Delegemizin sakladığı metot listesini döndürür. Örnek kullanımı şu şekildedir:

            // delegenin sakladigi metodlar listeleniyor
            foreach (Delegate d in mathOp.GetInvocationList())
            {
                Console.WriteLine("Method Name: {0}", d.Method);
                //SimpleMath static oldugu icin bos gelecektir
                Console.WriteLine("Type Name: {0}", d.Target);
            }

Örnek Proje: DelegateExample.rar