:::: MENU ::::

Delegeler

C#’ da delegeler Method tutan özel sınıflardır. Delege bir methodu alır, onu tutar ve biz istediğimizde onu çağırır. Methodlar aslında makine kodlarından oluşan ardışıl bir kod grubudur. Bir method başlangıç adresi yoluyla tutulup çağırılabilir. Yani delegenin bir methodu tutması, onun yalnızca başlangıç adresini tutması anlamına gelir.

Delege bildiriminin genel biçimi şöyledir;

delegate ([parametre bildirimi]);

Örneğin:

delegate void Proc(int a);

Görüldüğü gibi delege bildirimi, bir method bildirimi gibi yapılmaktadır. Burada Proc bir method değildir, bir sınıftır. Delege bir sınıftır.

Örneğin:


delegate int Test(int a,int b);

Bir delege her türlü methodu tutamaz. Geri dönüş değeri ve parametrik yapısı belli bir biçimde olan methodları tutabilir. Zaten delege bildiriminde delegenin hangi türden methodları tutabileceği bildirilmektedir. Yukarıdaki örnekte Proc isimli delege sınıfı geri dönüş değeri void olan, parametrik yapısı int olan methodları tutabilir. Parametre değişkeninin isminin bir önemi yoktur. Test isimli delege ise geri dönüş değeri int, parametrik yapısı int, int olan methodları tutabilir.

Delegeler kategori olarak referans türüne ilişkindir. Yani biz bir delege türünden değişken bildirdiğimizde bir referans bildirmiş oluruz. Delege nesnelerinin kendisi yine new operatörüyle yaratılmaktadır. Derleyici delege sınıfları için Default başlangıç methodu yazmaz fakat tek parametreli bir başlangıç methodu yazar. Bu tek parametreli başlangıç methodu. Tutulacak methodun adresini bizden almaktadır.

Bir methodun ismi (method çağırma operatörü olmadan) o methodun başlangıç adresini belirtmektedir. Delege sınıflarının tutulacak methodu alan bir başlangıç methodu vardır.

delegate void Proc(int a);
Proc p = new Proc(Sample.Foo);


d bir delege referansı olmak üzere d(…) ifadesi d delegesinin tuttuğu methodun çağırılması anlamına gelir. Bu ifadeden çağırılan methodun geri dönüş değeri elde edilir.


using System;
using System.Collections;

namespace CSD
{
	class App
	{
		public static void Main()
		{
			Proc d1,d2;

			d1 = new Proc(Sample.Add);
			
			int val;

			val = d1(100, 200);
			Console.WriteLine(val);

			d2 = new Proc(Sample.Multiply);

			val = d2(100, 200);
			Console.WriteLine(val);
		}
	}

	class Sample
	{
		public static int Add(int x, int y)
		{
			return x + y;
		}
		public static int Multiply(int x, int y)
		{
			return x * y;
		}
	}
	delegate int Proc(int a, int b);
}

Aynı isimli pek çok method bulunabilir. Fakat bunların parametrik yapıları aynı olamaz. Dolayısıyla bu durumda delegenin parametrik yapısına uygun olan method tutulmuş olur.

Örneğin:


delegate int Test(int a, int b);
//…
Test t = new Test(Math.Max);	//Math.Max’ lardan int, int parametresi  tutuluyor!

Aynı türden iki delege referansı birbirine atanabilir. Bu durumda iki referans aynı delege nesnesini gösteriyor duruma gelir.

Bir delege static olmayan methodları da tutabilir. Bu durumda method sınıf ismiyle değil bir referansla delegeye verilmelidir.

Örneğin:


			delegate void Proc();
			Sample s = new Sample();
			Proc p = new Proc(s.Foo);

Burada artık biz p() ile delege methodunu çağırsak delegenin tuttuğu method verilen referansla çağırılır. Yani p() ile s.Foo() aynı anlamdadır.

 

using System;
using System.Collections;

namespace CSD
{
	class App
	{
		public static void Main()
		{
			Sample s = new Sample(100);
			Proc p = new Proc(s.Foo);
			p();
		}
	}

	class Sample
	{
		private int m_val;

		public Sample(int val)
		{
			m_val = val;
		}

		public void Foo()
		{
			Console.WriteLine(m_val);
		}
	}
	delegate void Proc();
}

Delegenin tutacağı method ismi niteliksiz olarak da belirtilebilir. Bu durumda isim arama kuralına göre aranır. Static bir method olarak bulunursa sanki sınıf ismiyle, static olmayan bir isimle bulunursa sanki this referansıyla belirtilmiş gibi işlem görür.

Bir methodun parametre değişkeni bir delege türünden olabilir. Biz böyle bir methodu bir delege referansıyla çağırmak zorundayız.

Örneğin:

using System;
using System.Collections;

namespace CSD
{
	class App
	{
		public static void Main()
		{
			int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
			ForEach(a, new Proc(Disp));
		}
		public static void ForEach(int[] a, Proc p)
		{
			foreach (int x in a)
				p(x);
		}
		public static void Disp(int a)
		{
			Console.WriteLine(a);
		}
	}
	delegate void Proc(int a);
}

Delegeler neden kullanılır?

Bazen bir takım olaylar gerçekleştiğinde bizim bir methodumuzun çağırılmasını isteyebiliriz. Örneğin bir düğmeye tıklandığında belirlediğimiz bir methodun çağırılması istenebilir. Bu tür durumlarda bizden bir delege nesnesi istenir, bizde bir methodu delege nesnesine yerleştirerek ona veririz. Bizden delege nesnesi alan taraf olay gerçekleştiğinde delege methodlarını çağıracaktır.

Örneğin System.Threading isim alanında bulunan Timer sınıfı, verdiğimiz bir methodu arka planda periyodik çağırmaktadır. Timer sınıfının başlangıç methodunda biz çeşitli bilgileri ona veririz, sınıfta bu işi yapar. Timer sınıfının başlangıç methodu şöyledir.

public Timer( TimerCallback callback, object state, int dueTime, int period)

Methodun birinci parametresi çağırılacak methodu temsil eden delege türündendir. TimerCallback isimli delege şöyle bildirilmiştir;

Public delegate void TimerCallback(Object state)

Methodun ikinci parametresi delege methoduna geçirilecek parametreyi temsil eder. Üçüncü parametre periyodik çağırmaya ne kadar süre sonra başlanacağını belirtir. Son parametre periyodu belirtmektedir.


using System;
using System.Collections;
using System.Threading;

namespace CSD
{
	class App
	{
		public static void Main()
		{
			TimerCallback tc = new TimerCallback(Disp);

			Timer t = new Timer(tc, null, 0, 1000);

			Console.ReadLine();
		}

		public static void Disp(object o)
		{
			Console.Write("*");
		}
	}
}
using System;
using System.Collections;
using System.Threading;

namespace CSD
{
	class App
	{
		public static void Main()
		{
			TimerCallback tc = new TimerCallback(Disp);

			Timer t = new Timer(tc, null, 0, 1000);

			Console.ReadLine();
		}

		public static void Disp(object o)
		{
			DateTime dt = DateTime.Now;
				Console.Write("{0:D2}:{1:D2}:{2:D2}\r",dt.Hour,dt.Minute, dt.Second);
		}
	}
}

Kaynak:Kaan Aslan Hocanın Dersinde Tuttuğum Ders Notlarıdır.


So, what do you think ?