یک Delegate نوعی اشارهگر است به توابع در سی شارپ که میتواند ارجاعی را به یک یا چند تابع بخصوص داشته باشد. منظور از توابع در سی شارپ، متدها هستند. امضای یک Delegate باید با متدی که به آن اشاره میکنید یکی باشد.
در کلاس Employee بالا، تعدادی فیلد و یک متد با نام IncreaseSalary داریم که وظیفهی آن افزایش 30% حقوق کارمندانی است که کمتر از 10000 میگیرند. اگر در آینده قصد داشته باشیم که علاوه بر این افزایش حقوق، منطق دیگری را با میزان ترفیع و شایستگی کارمندان نیز لحاظ کنیم، لازم است کدهای متد IncreaseSalary را تغییر دهیم که این کار، یک کار خسته کننده است و شاید ما دوست نداشته باشیم تا کدهای کلاس پایهی Employee را تغییر دهیم. در این نوع سناریوها میتوان با استفاده از Delegateها، منطق افزایش حقوق و منطق ترفیع و شایستگی کارمندان را از هم جدا کرد. خوب، اولین کار، ویرایش متد IncreaseSalary است:
همانطور که در کد بالا قابل مشاهده است، منطق افزایش حقوق بر اساس ترفیع و شایستگی کارمندان را با Delegate ایی به نام SalaryIncreaseEligibility جدا کردهایم. بدین وسیله میتوانیم منطق شناسایی کردن کارمندان لایق افزایش حقوق را بدون ایجاد تغییری در کلاس Employee سفارشی کنیم. حال بگذارید متد IncreaseSalary از کلاس Employee را با منطق سفارشی خود برای افزایش حقوق کارمندان لایق، با کمک Delegate ایی به نام SalaryIncreaseEligibility اجرا کنیم.
در کد بالا ما منطق ترفیع و شایستگی کارمندان را از متد SalaryEligibility جدا کردهایم و این منطق را به کمک Delegate ای به نام SalaryIncreaseEligibility به متد ذکر شده پاس دادهایم. در آینده اگر قصد داشته باشیم تا این افزایش حقوق را بر اساس منطق دیگری تعریف کنیم، فقط کافیست که متد SalaryEligibility را تغییر دهیم و دیگر لازم نیست تغییری در کلاس Employee ایجاد کنیم.
using System; using System.Windows.Forms; namespace CSharpDelegates { public delegate void Display(string sMsg); public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { Display del = new Display(ShowMessage); del("This is an example for delegate"); } private void ShowMessage(string strMessage) { MessageBox.Show(strMessage); } } }
همانطور که در کد بالا مشاهده میکنید، Delegateها بسیار شبیه به کلاسها هستند. میتوانیم از آنها یک شیء ساخته و نام متدی را که قرار است به آن اشاره کند، از طریق سازنده به آن ارسال کنیم. در کد بالا یک Delegate را با نام Display ساختهایم که به متد ShowMessage اشاره میکند. اگر به Delegate و متد ShowMessage دقت کنید خواهید دید که هر دو دارای پارامتر ورودی و امضای یکسانی هستند. ما شیءای به نام Display را از نوع Delegate ساختهایم که متدی به نام ShowMessage را با پارامتر ورودی از نوع string، اجرا میکند.
شاید بپرسید که چرا باید از Delegate استفاده کنیم؟ چرا متد ShowMessage را مستقیما اجرا نکنیم؟
خوب، Delegateها برای طراحی فریم ورکهایی با قابلیت استفادهی مجدد از کدهای آنها، بسیار مناسب هستند. بگذارید این مطلب را با یک مثال ساده از کلاس Employee توضیح دهیم.
ویژال استودیو را باز کنید و یک پروژهی Windows Forms Application ساده را با نام CSharpDelegates بسازید. سپس کلاس زیر را به آن اضافه کنید:
using System.Collections.Generic; namespace CSharpDelegates { public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public int Experience { get; set; } public double Salary { get; set; } public void IncreaseSalary(List<Employee> Employees) { foreach (Employee emp in Employees) { if (emp.Salary < 10000) { emp.Salary = emp.Salary + emp.Salary * 0.3; } } } } }
using System.Collections.Generic; namespace CSharpDelegates { public delegate bool SalaryIncreaseEligibility(Employee emp); public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public int Experience { get; set; } public double Salary { get; set; } public string IncreaseSalary(List<Employee> Employees, SalaryIncreaseEligibility del) { string sSalIncreasdEmployees = "Salary increased for "; foreach (Employee emp in Employees) { if (del(emp)) { emp.Salary = emp.Salary + emp.Salary * 0.3; sSalIncreasdEmployees = sSalIncreasdEmployees + emp.Name + " ,"; } } return sSalIncreasdEmployees; } } }
using System; using System.Collections.Generic; using System.Windows.Forms; namespace CSharpDelegates { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { List<Employee> empList = new List<Employee>(); empList.Add(new Employee() { EmployeeId = 100, Name = "Mark", Salary = 2000, Experience = 3 }); empList.Add(new Employee() { EmployeeId = 101, Name = "John", Salary = 15000, Experience = 8 }); empList.Add(new Employee() { EmployeeId = 102, Name = "David", Salary = 4000, Experience = 4 }); empList.Add(new Employee() { EmployeeId = 103, Name = "Bob", Salary = 50000, Experience = 14 }); empList.Add(new Employee() { EmployeeId = 104, Name = "Alex", Salary = 9000, Experience = 6 }); SalaryIncreaseEligibility del = new SalaryIncreaseEligibility(SalaryEligibility); Employee objEmp = new Employee(); string sMsg = objEmp.IncreaseSalary(empList, del); MessageBox.Show(sMsg); } private bool SalaryEligibility(Employee emp) { if (emp.Salary > 10000) { return true; } else { return false; } } } }