تعریف Delegates در زبان #C
اگر بخواهیم تابعی را به عنوان پارامتر ارسال کنیم چه می شود؟ زبان سی شارپ چگونه توابع callback یا event handler را مدیریت می کند؟ برای انجام این کار از delegate استفاده می کنیم.
Delegate در لغت به معنای نماینده است و در #C به معنای الگوی توابع می باشد. Delegate ها، در حقیقت data type هایی هستند که می توانند یک متد را داخل خود ذخیره کنند. برای مثال، زمانی که متغیری از نوع int تعریف کردید، می توانید مقداری از نوع int در آن قرار دهید، delegate ها دقیقاً همین کار را برای متدها انجام می دهند.
Function Pointers در زبان ++C دقیقاً معادل مفهوم delegate ها در زبان سی شارپ هستند که در این آموزش قصد داریم با آن ها آشنا شویم. هر data type ای در زبان سی شارپ باید تعریف شود، مانند کلاس ها که به ما اجازه تعریف Reference Type ها را می دهند یا struct ها که می توان با کمک آن ها Value Type ها را تعریف کرد. delegate یک نوع داده نوع مرجع است که signature یک متد را تعریف می کند. شما می توانید متغیرهای delegate را مانند سایر انواع داده ها تعریف کنید که می توانند به هر متدی با همان signature به عنوان delegate اشاره کنند.
در حین کار با delegates سه مرحله وجود دارد:
1- تعریف delegate
2- تعیین تابع هدف
3- فراخوانی delegate
یک delegate را می توان با استفاده از کلمه کلیدی delegate و به دنبال آن یک signature تابع (function signature)، همانطور که در زیر نشان داده شده است، اعلام کرد.
در ادامه یک delegate به نام MyDelegate تعریف شده است.
در بالا، یک delegate با نام MyDelegate با نوع بازگشتی void و پارامتر رشته ای تعریف کرده ایم. یک delegate می تواند خارج از کلاس یا داخل کلاس تعریف شود. عملاً بهتر است که خارج از کلاس اعلام شود.
پس از تعریف delegate، باید متد هدف یا lambda expression را تنظیم کنیم. می توانیم با ایجاد یک شی از delegate با استفاده از کلمه کلیدی new و ارسال متدی که signature آن با signature مربوط به delegate مطابقت دارد، این کار را انجام دهیم.
در قطعه کد بالا به دلیل ویژگی top-level statements تعریف delegate را در پایین کد قرار داده ایم.
می توانید با اختصاص مستقیم یک متد بدون ایجاد یک شیء از delegate، متد هدف را تنظیم کنید، به عنوان مثال:
MyDelegate del = MethodA
پس از تنظیم یک متد هدف، یک delegate می تواند با استفاده از متد ()Invoke یا با استفاده از عملگر () فراخوانی شود.
در ادامه مثال کاملی از delegate نشان داده شده است. ابتدا کلاس ClassA را به صورت زیر تعریف می کنیم.
در ادامه کلاس دیگری با نام ClassB تعریف می کنیم.
در ادامه در کلاس program داریم:
در نهایت خروجی قطعه کد بالا به صورت زیر می باشد.
برای وضوح بیشتر تصویر زیر نحوه تعریف و استفاده از delegate در زبان سی شارپ را نشان می دهد.
ارسال Delegate به عنوان پارامتر
یک متد می تواند پارامتری از نوع delegate داشته باشد، همانطور که در زیر نشان داده شده است.
خروجی قطعه کد بالا به صورت زیر می باشد.
در دات نت، انواع Func و Action ،Delegate های عمومی داخلی هستند که به جای ایجاد delegate های سفارشی جدید، باید برای اکثر delegate های معمولی استفاده شوند.
Multicast Delegate
delegate می تواند به چندین متد اشاره کند. یک delegate که به چندین متد اشاره می کند، Multicast Delegate نامیده می شود. عملگر "+" یا "+=" یک تابع را به لیست فراخوانی اضافه می کند و عملگر "-" و "-=" آن را حذف می کند. در ادامه مثالی از Multicast Delegate نشان داده شده است.
خروجی قطعه کد بالا به صورت زیر می باشد.
عملگرهای جمع و تفریق همیشه به عنوان بخشی از انتساب عمل می کنند: del1 += del2 که دقیقاً معادل del1 = del1+del2 است و برای تفریق نیز به همین شکل است.
اگر delegate مقداری را برگرداند، زمانی که یک multicast delegate فراخوانی می شود، آخرین مقدار متد هدف اختصاص داده شده برگردانده می شود. مثال زیر یک multicast delegate که مقداری را بر می گرداند نشان داده شده است.
خروجی قطعه کد بالا به صورت زیر می باشد.
Generic Delegate
delegate عمومی (generic delegate) را می توان به همان روش تعریف delegate تعریف کرد، اما با استفاده از پارامترهای نوع عمومی (generic type) یا نوع بازگشتی. هنگام تنظیم یک متد هدف، نوع عمومی باید مشخص شود.
به عنوان مثال، delegate عمومی زیر را در نظر بگیرید که برای پارامترهای int و string استفاده می شود.
خروجی قطعه کد بالا به صورت زیر می باشد.
delegate همچنین برای تعریف Event و Anonymous Method استفاده می شود.
نکاتی که باید در مورد delegate در زبان برنامه نویسی C# به خاطر بسپارید:
1- delegate نوع داده نوع reference است که signature را تعریف می کند.
2- متغیر نوع delegate می تواند به هر متدی با signature مشابه با delegate اشاره کند.
3- سینتکس: [تعیین کننده سطح دسترسی] delegate [نوع بازگشتی] [نام delegate] ([پارامترها])
4- signature متد هدف باید با signature مربوط به delegate مطابقت داشته باشد.
5- delegates را می توان مانند یک تابع عادی یا متد ()Invoke فراخوانی کرد.
6- چندین متد را می توان با استفاده از عملگر "+" یا "+=" به delegate اختصاص داد و با استفاده از عملگر "-" یا "-=" حذف کرد. به این عمل Multicast delegate می گویند.
7- اگر یک multicast delegate مقداری را بر گرداند، آنگاه مقدار را از آخرین متد هدف اختصاص داده شده برمی گرداند.
8- delegate برای تعریف event و متدهای anonymous در سی شارپ استفاده می شود.