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 گفته میشود.
به تعریف 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 استفاده کنیم.