Delegates and Events


Delegates

Delegates از نوع های مرجع به شمار می آیند که اجازه ی فراخوانی غیر مستقیم توابع را میسر می کنند. نمونه ی ایجاد شده از Delegates ریفرنسی را از چندین تابع در خود نگه می دارد و با فراخوانی یک Delegate تمام این توابع اجرا می گردند. و همانطور که در قسمت های پیشین نیز ذکر شد این مفهوم معادل function pointers در C++‎ می باشد. در اینجا دو نکته را باید به خاطر سپرد:
1- Delegates از نوع های مرجع به شمار می آیند و نه نوع های عددی. (نوع های ریفرنس مانند رشته ها و اشیاء ...)
2- یک Delegate می تواند ارجاعی از چندین متد را در خودش نگه دارد.



تعریف و مقدار دهی اولیه ی Delegates :

یک Delegate را می توان در فضای نام خاص خودش و یا در یک کلاس تعریف نمود. در هر حالت این تعریف از System.MulticastDelegate مشتق شده است.
هر delegate به نگهداری مرجعی از توابع با نوعی ویژه محدود می گردد. مثال زیر را در نظر بگیرید:



کد:
public delegate void Print (String s);
از این delegate برای ارجاع به توابعی که تنها دارای یک پارامتر ورودی از نوع رشته و بدون هیچگونه خروجی می باشند ، استفاده می شود. برای مثال فرض کنید که کلاسی حاوی متد زیر باشد:




کد:
1.	public void realMethod (String myString)
2.	{
3.	    // method code
4.	}
متدی دیگر در این کلاس می تواند 'Print' delegate را به شکل زیر نمونه سازی کند:



کد:
Print delegateVariable = new Print(realMethod);
که در حقیقت مرجعی از 'realMethod' را در خود نگه می دارد.


نکته : 'multicast delegates'

این نوع delegates می توانند همزمان به متدهای مختلفی ارجاع نمایند. این نوع ها حتما باید خروجی void داشته باشند. برای کار با multicast delegates می توان از عملگر های + و یا – نیز برای اضافه و یا کم نمودن مراجع به آنها استفاده نمود. برای مثال:



کد:
1.	Print s = null;
2.	s = s + new Print (realMethod);
3.	s += new Print (otherRealMethod);
مثال زیر روش استفاده از delegates را در عمل بیان می کند:






کد:
1.	using System;
2.	using System.IO;
3.	
4.	public class DelegateTest
5.	{
6.	    public delegate void Print (String s);
7.	
8.	    public static void Main()
9.	    {
10.	        Print s = new Print (toConsole);
11.	        Print v = new Print (toFile);
12.	        Display (s);
13.	        Display (v);
14.	    }
15.	
16.	    public static void toConsole (String str)
17.	    {
18.	        Console.WriteLine(str);
19.	    }
20.	
21.	    public static void toFile (String s)
22.	    {
23.	        File f = new File("fred.txt");
24.	        StreamWriter fileOut = f.CreateText();
25.	        fileOut.WriteLine(s);
26.	        fileOut.Flush();
27.	        fileOut.Close();
28.	    }
29.	
30.	    public static void Display(Print pMethod)
31.	    {
32.	        pMethod("This should be displayed in the console");
33.	    }
34.	}
در متد Main مثال فوق ، Print delegate دوبار نمونه سازی شده و پارامترهای متفاوتی را پذیرفته است. سپس این delegate ها به تابع Display پاس شده اند.



Events

مثالی ساده از بحث رویدادها و رویداد گردانی کلیک کردن کاربر بر روی یک دکمه و سپس نتیجه ی آن بکار افتادن چندین متد برای مدیریت این آن می باشد. تفاوت متدهای رویداد با متدهای معمولی در این است که آنها باید به صورت خارجی فراخوانی شوند. هر گونه تغییر داخلی در وضعیت برنامه می تواند بعنوان یک رخداد در نظر گرفته شود.
رویداد ها از مدل 'subscription-notification' پیروی می کنند. یک کلاس دلخواه باید قادر به subscription در یک رخداد خاص باشد و سپس هنگامی که رخدادی رویداد یک notification را دریافت کند.
Delegates و خصوصا multicast delegates ، مدل فوق را عینیت می بخشند.

مثال زیر نشان می دهد که چگونه کلاس 2 در رخداد صادر شده از طرف کلاس 1 آبونه میشود:

1- کلاس یک صادر کننده ی رخدادهای E می باشد. این کلاس حاوی public multicast delegate D است.
2- کلاس دو توسط متد رویداد گردان M می خواهد به این رویداد عکس العمل نشان دهد. بنابراین به D ریفرنسی از M را اضافه می نماید.
3- کلاس یک هنگامی که خواست رخداد E را صادر کند تنها کافی است که متد D را فراخوانی نماید. این امر سبب می شود تمام متدهای آبونه شده در رخداد E ، فراخوانی گردند.


از واژه ی کلیدی 'event' برای تعریف multicast delegates استفاده می گردد . به مثال زیر دقت نمایید:




کد:
1.	public class EventIssuer
2.	{
3.	    public delegate void EventDelegate(object from, EventArgs args);
4.	    public event EventDelegate myEvent;
5.	
6.	    public void issueEvent(EventArgs args)
7.	    {
8.	        myEvent(this, args);
9.	    }
10.	}
در مثال فوق کلاس EventIssuer حاوی تعریف رویداد myEvent است. هنگامیکه متد issueEvent فراخوانی می گردد ، رخداد myEvent نیز فراخوانی می شود. اگر کلاسی توسط EventIssuer ei ، تمایل داشت در این رویداد آبونه شود باید به صورت زیر عمل نماید:



کد:
ei.myEvent += new EventIssuer.EventDelegate(handleEvents);
مرجع این قسمت :

راهنمای همراه Borland C#‎ builder قسمت Softsteel Solutions C#‎ Tutorial .