PDA

View Full Version : مقاله: Custom Event Handling in C# - Part1 : Delegates



hdv212
چهارشنبه 23 مرداد 1387, 12:43 عصر
Custom Event Handling in C#
Delagets :
در این سری از مقالات قصد دارم تا شما رو با مبحث Event Handling در سی شارپ آشنا کنم، به علت فقدان منابع فارسی در این مورد، بر آن شدم تا دانش و تجربیات خودم رو در این زمینه در اختیار شما عزیزان قرار بدم.
اولین موضوعی که میخواهیم در مورد اون صحبت کنیم، انواع delegate هستند. Delegateها در سی شارپ یکی از نقشهای مهم و کلیدی رو ایفا میکنند و با توجه با ماهیت اونا، امکانات متفاوتی رو در اختیار ما قرار میدن، از جمله، استفاده از آنها در MultiThread Application، Asynchronous Programming و Event Handling که بعدا در این مورد به تفصیل صحبت خواهیم کرد. و اما Delegate چیست ؟ یکی از تعاریفی که در مورد delegate ها به کار برده میشه رو ملاحظه بفرمایید :

Delegate یک اشاره گر به تابع است (function pointer)

تعریف بالا با توجه به اینکه غلط نیست، اما کامل هم نیست، در حقیقت delegate آبجکتی است که رفرنسی از یک متد یا مجموعه ای از متدها رو در خودش نگه میداره. اما این مجموعه متدها بایستی از یک سری قوانین تبعیت کنند تا بتونن به لیست متدهایی که اون delegate بهشون اشاره میکنه اضافه بشن، به عبارت دیگه برای اینکه متدی به لیست Reference Method های یک delegate اضافه بشه باید با تعریف اون delegate هماهنگ باشه، به این هماهنگی و تطابق اصطلاحا امضا (Signature) میگن، پس مجوز ورود یک متد به لیست Reference Method یک delegate اینه که امضای اون متد با تعریف delegate مورد نظر یکی باشه، به این ترتیب که :

1. نوع بازگشتی متد مورد نظر برابر با نوع بازگشتی مشخص شده در تعریف delegate باشه.
2. نوع و تعداد پارامترهای ورودی متد مورد نظر برابر با نوع و تعداد پارامترهای ورودی مشخص شده در تعریف delegate باشه.

لازم به ذکر است که به لیست Reference Methods مربوط به یک delegate اصطلاحا Invocation List گفته میشود.


http://i36.tinypic.com/iqd5qg.jpg

به تعریف delegate زیر نگاه کنید :

public delegate void myDelegate(string argument);
طبق تعریف delegate مورد نظر، نام delegate ما myDelegate است و متدهایی را میتواند به Invocation List خود اضافه کند که :

1. هیچ مقداری بر نگردانند.
2. یک پارامتر از نوع string بگیرند.

به این متد نگاه کنید :

private void myMethod(string msg)
{
// method body
}
همانطور که در کد بالا میبینید، امضای متد myMethod با تعریف myDelegate مطابقت دارد، پس این متد میتواند به Invocation List آبجکت myDelegate ما اضافه شود :

myDelegate del = new myDelegate(myMethod);
متد myMethod اولین متدی است که به Invocation List آبجکت myDelegate یعنی del اضافه میشود، برای اضافه کردن متدهای بیشتر بایستی به شیوه ی زیر عمل کنیم :

del += new myDelegate(myMethod2);
همچنین برای حذف یک متد از Invocation List یک آبجکت delegate میبایست به شیوه ی زیر عمل نماییم :

del -= new myDelegate(myMethod2);
حال، این متد را در نظر بگیرید :

private void myMethod3()
{
// method body
}
آیا این متد میتواند به Invocation List آبجکت del اضافه شود ؟ پاسخ منفی است، به دلیل اینکه امضای آن با امضای delegate اعلان شده ی ما مطابقت ندارد (هیچ پارامتری دریافت نمیکند).
حال اگر آبجکت delegate مورد نظر را Invoke کنیم، تمام متدهایی که در Invocation List آن موجود هستند اجرا میشوند، نحوه ی Invoke کردن یک آبجکت delegateمانند فراخوانی یک متد و ارسال پارامتر (در صورت نیاز) به آن میباشد :

del("my message value");
خب، حالا هرچی یاد گرفتیم رو میخواهیم در قالب یک پروژه ی Console Application پیاده سازی نماییم، پس یک پروژه از نوع Console Application بسازید و کد زیر رو در آن وارد نمایید :

class Program
{
delegate void myDelegate(string argument);
static void Main(string[] args)
{
myDelegate del = new myDelegate(myMethod);
del += new myDelegate(myMethod2);
del("sample string value");

Console.Read();
}

private static void myMethod(string msg)
{
Console.WriteLine(msg+" from myMethod");
}

private static void myMethod2(string msg)
{
Console.WriteLine(msg + " from myMethod2");
}
}

خب، با Invoke شدن آبجکت del هر دو متد myMethod و myMethod2 اجرا میشوند و خروجی آنها نمایش داده میشوند.

چرا در Event ها از Delegate استفاده میکنیم ؟
اگر delegate، فراخوانی ساده ی یک متد به صورت غیر مستقیم است، پس چه نیازی هست که از delegate استفاده کنیم ؟
پاسخ این است، کامپوننتهایی که شامل رویداد های مختلفی هستند را در نظر بگیرید، در زمان تولید نرم افزار شما کنترلی را به فرمتون اضافه میکنید و در صورت لزوم، رویدادهای مختلف آن را مدیریت میکنید، زمانی که شما رویدادی رو Handle میکنید، در حقیقت متدی رو در Invocation List آبجکت delegate درون کنترلتون اضافه یا Register کردید، متدی شبیه متد زیر :

private void anyMethod(object sender, EventArgs e)
{
// method body
}

کنترل شما، حقیقتا هیچ اطلاعی در مورد متد مورد نظر نداره، فقط میدونه که این متد با امضای تعریف Delegate درونی خودش مطابقت داره و به Invocation List اش اضافه شده و هر زمان که آبجکت delegate مورد نظر Invoke شد، اونو اجرا میکنه، در حقیقت شما با ایجاد یک متد Event Handler در سورس کدتون، اونو دارید به delegate درون کنترل مورد نظر پیوند میدید (با توجه به تطابق امضای متد با delegate) و آبجکت delegate مورد نظر بدون اینکه اطلاعی در مورد متدهای رجیستر شده در Invocation List اش داشته باشه، اونها رو به صورت غیر مستقیم در زمان Invoke شدن خودش اجرا میکنه. این مهمترین دلیل استفاده از delegate ها در مدیریت رویداد میتونه باشه.

ساختار درونی Delegate :
زمانی که شما delegate ای رو اعلان میکنید، کامپایلر C# با توجه به اعلان delegate شما، کلاسی رو به assembly خروجی اضافه میکنه که نام کلاس مورد نظر، برابر با نام delegate شما و متدهای کلاس مورد نظر دارای امضایی مطابق delegate شما میباشند، این کلاس از کلاسی به نام System.MulticastDelegate مشتق میشه و دارای متدهایی است که امضای اونا با delegate شما مطابقت داره (متدهایی با نام Invoke,BeginInvoke و EndInvoke) که متد Invoke برای Synchronous Invocation و BeginInvoke و EndInvoke هم برای Asynchronous Invocationبه کار برده میشوند. لازم به ذکر است که شما نمی توانید خودتان کلاسی رو از System.MulticastDelegate مشتق کنید، تنها کامپایلر C# مجاز به چنین کاری می باشد، به عبارت دیگه با اعلان یک delegate شما به کامپایلر C# میگویید که کلاسی رو طبق delegate تعریف شده ی شما از System.MulticastDelegate مشتق کنه.

اما علت نامی که برای System.MulticastDelegate در نظر گرفته شده (Multicast) اینه که، delegate میتونه ارجاع بیشتر از یک متد رو در خودش نگه داره، و در زمان Invoke شدن، تمام رفرنس های متدهایی که در Invocation List اش وجود دارد رو فراخوانی کنه.

البته مبحث Delegate و همینطور موارد استفاده ی آنها بسیار وسیع تر از حیطه ی این مقاله س،
مثلا شما میتونید delegate هایی که دارای امضاهای مشابه هستند رو با هم جمع کنید و در یک delegate جدید ذخیره نمایید، حاصل delegate ای خواهد شد که Invocation List آن برابر با مجموع Invocation Listهای delegate های جمع شده است، میتونید از delegate ها در برنامه های MultiThread استفاده کنید و یا اونها رو در Asynchronous Programming به کار ببرید و ...
خب، بخش اول مقاله ی Custom Event Handling که به Delegateها اختصاص داشت، تمام شد، در مقاله ی بعدی سعی خواهیم کرد به صورت عملی از delegate ها در Event Handling استفاده کنیم.

موفق باشید - حامد وزیری

simina
سه شنبه 02 مهر 1387, 11:54 صبح
az shoma mamnunam

reza6384
شنبه 04 آبان 1387, 23:36 عصر
سلام. واقعا ممنون. توضیح بسیار عالی ای بود.


در مقاله ی بعدی سعی خواهیم کرد به صورت عملی از delegate ها در Event Handling استفاده کنیم.


بخش بعدی کجاست قربان؟

odiseh
یک شنبه 05 آبان 1387, 11:32 صبح
سلام حامد خان
مرسی از این مقاله جالبت
میشه لطف کنی بگی که دقیقا ارتباط یه Control با Delegate Object مرتبط با اون چیه؟ هر کنترلی فقط یک Delegate Object داره؟ هر Delegate Object می تونه با بیش از یه Control کار کنه و .....
اگه توضیحات بیشتری بخواهیم میشه منبع معرفی کنی. بازم تشکر

hdv212
پنج شنبه 07 آذر 1387, 18:07 عصر
میشه لطف کنی بگی که دقیقا ارتباط یه Control با Delegate Object مرتبط با اون چیه؟ هر کنترلی فقط یک Delegate Object داره؟
سلام به شما و ممنون به خاطر حسن توجهتون
باید عرض کنم که درست متوجه سوال شما نشدم اما در تعریف هر کنترل با توجه به نوع رویدادهایی که میتونه Handle کنه، delegateهای مختلفی رو استفاده میکنه و این کاملا به خود کنترل بر میگرده.
فکر میکنم خواندن این مقاله (http://www.codeproject.com/KB/cs/events.aspx) خالی از لطف نباشه.
موفق باشید

emad_67
پنج شنبه 07 آذر 1387, 19:43 عصر
سلام جناب hdv212 (http://barnamenevis.org/forum/member.php?u=14084) و خیلی ممنون بابت مقاله خوبت
یه سوالی برای من پیش اومد در این رابطه.
فرق delegate با event ها در چی هست؟ مثلا مثال شما را یه مقدار تغییر دادم به این شکل:
اول یه کلاس با نام test تعریف کردم:


class test
{
public delegate void myDelegate(string argument);
public myDelegate del;
public void Invoke(string msg)
{
if (del != null)
del(msg);
}
}

و توی main هم اینو قرار دادم:


class Program
{

static void Main(string[] args)
{
test obj = new test();
obj.del += new test.myDelegate(myMethod);
obj.del += new test.myDelegate(myMethod2);
obj.Invoke("Hello");
Console.Read();
}

private static void myMethod(string msg)
{
Console.WriteLine(msg + " from myMethod");
}

private static void myMethod2(string msg)
{
Console.WriteLine(msg + " from myMethod2");
}
}

الان استفاده از delegate دقیقا مثل یه event کار میکنه پس تفاوتش با وقتی که یک event به شکل زیر تعریف میکنیم چیه؟:


public event myDelegate del;

با تشکر

hdv212
یک شنبه 10 آذر 1387, 12:22 عصر
درسته، event ها خیلی شبیه به delegate ها هستند، در حقیقت، event ها شکل ساده ای از delegate ها هستند که برای هدف خاصی طراحی شدند : مدیریت رویداد.
یک نکته ی دیگه اینکه هر event ای دارای یک delegate درونی میباشد و شما مثل هر delegate ای میتونید بهش متد اضافه کنید و حذف کنید، وقتی event ای raise میشه، delegate درونی خودش رو invoke میکنه و به ترتیب تمام متدهایی که در invocation list اون ذخیره شدن رو اجرا میکنه.
در مثال شما، استفاده از delegate به جای event شاید در ظاهر مشکلی نداشته باشه، اما پیشنهاد نمیشه و Best Practise نیست.
برای اطلاعات بیشتر رجوع کنید به کتاب :
Apress - Illustrated C Sharp 2008 (http://www.apress.com/book/view/1590599543)
فصل 16، Events
موفق باشید

saed2006
دوشنبه 23 فروردین 1389, 10:24 صبح
قسمت دوم مقاله چی شد

tara_sh500
جمعه 26 مهر 1392, 00:27 صبح
بسیار عالی. دقیقا همون چیزهایی رو توضیح دادین که نمیدونستم. مرسی :تشویق: