A Delegate is a function pointer in C# which holds reference of the specific function or functions. Here function means method in C#. The signature of the delegate should be same as the signature of the function delegate points to, because of this delegates called as type safe function pointers. Let’s create simple delegate as shown below.
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);
}
}
}
As shown above a delegate is similar to a class, we can create the instance to the delegate and we have to pass function name as parameter to the delegate constructor to which delegate needs to point to. In the above example we have created the delegate Display which points to the method ShowMessage(). If you observe delegate Display and ShowMessage() method, both signatures(input parameter and return type) are same. We created the object for delegate Display and passed the input parameter as ShowMessage() method name. We called the method ShowMessage() by invoking the delegate Display with string input parameter.
You should get doubt here, why we have to call ShowMessage() method by creating delegate instead of calling the method directly like ShowMessage(("This is an example for delegate"); We will discuss about this below.
Delegates are very useful while developing framework level methods to make our framework code reusable. Let’s discuss about code reusability by using delegates with simple Employee example. Open Microsoft Visual Studio 2015 => Create simple Windows Application and name it as “CSharpDelegates” and add Employee class to that project as shown below.
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;
}
}
}
}
}
As shown above we have some automatic properties and a method IncreaseSalary() in the Employee class. IncreateSalary() method has a logic to increase the salary of the employee by 30% whose salary is less than 10000. In future if we want to increase the salary based promotion eligibility also, then again we have to change IncreaseSalary() method logic to include promotion eligibility logic which is tedious process and we don’t want to change code of our concrete class Employee. In this case we have to separate the logic for eligibility to increase the salary from the increase salary logic, delegates are very useful in this type of scenario. First let’s change Employee class IncreaseSalary() method just to include the logic for salary change as shown below. Here introduce a delegate for salary hike eligibility logic as shown below.
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;
}
}
}
As shown above we have separated the salary increase eligibility logic by creating the delegate SalaryIncreaseEligibility. We can have our own logic to identify the employees who are eligible for the salary hike without changing the concrete class Employee. Now let’s call the Employee class IncreaseSalary() method by creating our own salary increase eligibility logic and pass this logic with the help of delegate SalaryIncreaseEligibility as shown below.
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;
}
}
}
}
As shown above we have separated the salary eligibility logic in SalaryEligibility() method and passed this logic with the help of delegate SalaryIncreaseEligibility. In future if you want to increase the salary based on experience we just have to change the logic in SalaryEligibility() method without changing the framework level class Employee.
In my next article we will discuss about Multi Cast Delegates in C#.