در زبان سی شارپ یک متد میتواند شامل یک و یا چندین پارامتر با نوع های مختلف باشد. اما آیا میتوان از یک متد به عنوان پارامتر برای متدی دیگر استفاده کرد. با استفاده از Delegate میتوان این کار را انجام داد. در این فصل با Delegate ها در سی شارپ آشنا خواهیم شد.
Delegate
آیا می توان از یک تابع به عنوان پارامتر تابعی دیگر استفاده کرد؟ زبان سی شارپ چطور توابع callback را مدیریت میکند؟ جواب این سوال را می توان در delegate
ها پیدا کرد یک delegate همانند یک اشاره گر به توابع مورد نظر اشاره می کند. یک delegate ارجاعی از متد مورد نظر را در خود نگهداری میکند. همه جایگزین ها به شکل ضمنی از کلاس System.Delegate مشتق میشوند.
یک delegate میتواند با استفاده از کلمه کلیدی delegate
تعریف شود. قاعده نوشتاری delegate در زیر نشان داده شده است :
<access modifier> delegate <return type> <delegate_name>(<parameters>)
نمونه مثال زیر یک delegate با نام Print
را تعریف می کند :
public delegate void Print(int value);
از delegate تعریف شده در مثال بالا می توان برای اشاره به هر متدی که دارای مقدار بازگشتی و پارامترهای یکسان با آن باشد، استفاده کرد. به نمونه مثال زیر که یک delegate را تعریف و از آن استفاده کرده است توجه کنید :
class Program
{
// declare delegate
public delegate void Print(int value);
static void Main(string[] args)
{
// Print delegate points to PrintNumber
Print printDel = PrintNumber;
printDel(100000);
printDel(200);
// Print delegate points to PrintMoney
printDel = PrintMoney;
printDel(10000);
printDel(200);
}
public static void PrintNumber(int num)
{
Console.WriteLine("Number: {0,-12:N0}",num);
}
public static void PrintMoney(int money)
{
Console.WriteLine("Money: {0:C}", money);
}
}
خروجی نمونه مثال بالا به شکل زیر است :
Number: 10,000 Number: 200 Money: $ 10,000.00 Money: $ 200.00
در نمونه مثال بالا یک delegate با نام Print را تعریف کرده ایم که پارامتری با نوع داده ای int
را پذیرفته و مقدار بازگشتی آن void
است. در متد ()Main متغیری از نوع Print تعریف و با مقدار PrintNumber
مقدار دهی شده است.
اکنون فراخوانی delegate مربوطه متد PrintNumber را فراخوانی خواهد کرد. به همین طریق اگر delegate مورد نظر با متد PrintMoney
مقدار دهی شود، در هنگام فراخوانی آن متد را فراخوانی خواهد کرد. در شکل زیر ساختار یک delegate نشان داده شده است :
فراخوانی Delegate
یک delegate میتواند همانند یک متد فراخوانی شود و این به خاطر این است که ارجاعی از یک متد را در خود نگه میدارد. فراخوانی یک delegate باعث فراخوانی متدی خواهد شد که delegate مورد نظر به آن ارجاع کرده است. یک delegate میتواند به دو روش فراخوانی شود : با استفاده از عملگر ()
یا با استفاده از متد ()Invoke
. نمونه مثال زیر به خوبی این موضوع را نشان داده است :
Print printDel = PrintNumber;
printDel.Invoke(10000);
//or
printDel (10000);
خروجی نمونه مثال بالا به شکل زیر است :
Number: 200 Number: 200
ارسال Delegate به عنوان یک پارامتر
یک متد می تواند پارامتری از نوع delegate را داشته باشد و می تواند در بدنه خود آن را فراخوانی کند :
public static void PrintHelper(Print delegateFunc, int numToPrint)
{
delegateFunc(numToPrint);
}
در نمونه مثال بالا متد PrintHelper
دارای یک پارامتر delegate بوده و آن را همچون یک متد فراخوانی کرده است. نمونه مثال زیر نشان میدهد که چطور میتوان از متد PrintHelper استفاده نمود :
class Program
{
public delegate void Print(int value);
static void Main(string[] args)
{
PrintHelper(PrintNumber, 10000);
PrintHelper(PrintMoney, 10000);
}
public static void PrintHelper(Print delegateFunc, int numToPrint)
{
delegateFunc(numToPrint);
}
public static void PrintNumber(int num)
{
Console.WriteLine("Number: {0,-12:N0}",num);
}
public static void PrintMoney(int money)
{
Console.WriteLine("Money: {0:C}", money);
}
}
خروجی نمونه مثال بالا به شکل زیر است :
Number: 10,000 Money: $ 10,000.00
Multicast Delegate
یک delegate می تواند به چندین متد اشاره داشته باشد. به اینگونه delegate ها ، multicast
گفته میشود. عملگر جمع(+
) یک متد را به یک delegate اضافه کرده و عملگر تفریق(-
) یک متد را از آن حذف میکند :
public delegate void Print(int value);
static void Main(string[] args)
{
Print printDel = PrintNumber;
printDel += PrintHexadecimal;
printDel += PrintMoney;
printDel(100000);
}
public static void PrintNumber(int num)
{
Console.WriteLine("Number: {0,-12:N0}",num);
}
public static void PrintMoney(int money)
{
Console.WriteLine("Money: {0:C}", money);
}
public static void PrintHexadecimal(int dec)
{
Console.WriteLine("Hexadecimal: {0:X}", dec);
}
خروجی نمونه مثال بالا به شکل زیر است :
Number: 1,00,000 Hexadecimal: 186A0 Money: $ 1,00,000.00
همانطور که در نمونه مثال بالا مشاهده میکنید فراخوانی delegate مورد نظر باعث شده است هر سه متد فراخوانی شوند.