C# advanced-Part 2: Delegate, Anonymous Method and Lambda Expression

In this series we will learn about delegate, anonymous method and lambda expression.

Lembda.jpg

Delegate: A delegate is a type safe function pointer. That is, it holds a reference(pointer) to a function. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked.

The signature of the delegate must match the signature of the function, the delegate points to, otherwise you will get a compile time error. This is the reason the delegates are called as type safe function pointer.

An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match the delegate's. This makes delegates perfectly suited for "anonymous" invocation.

Following example demonstrate the use of delegate. Here I declared ChangeValue delegate, instantiating it and passing the method to it to point.

class Program
   {
       public delegate int ChangeValue(int number);
       static void Main(string[] args)
       {
           ChangeValue cv1 = new ChangeValue(AddNum);
           ChangeValue cv2 = new ChangeValue(MulNum);
           cv1(20);
           Console.WriteLine("Addnum ={0}", initialNumber);
           cv2(2);
           Console.WriteLine("Addnum ={0}", initialNumber);

           Console.ReadKey();
       }

       static int initialNumber = 10;

       public static int AddNumber(int num)
       {
           return initialNumber += num;
       }

       public static int MultiplyNumber(int num)
       {
           return initialNumber *= num;
       }
    }

Anonymous method: An anonymous method is a method without a name. Anonymous methods provide a technique to pass a code block as a delegate parameter. Anonymous methods are the methods without a name, just the body.

In the following program I am using an anonymous method to pass a code block to print a string using a delegate.

using System;

public delegate void PrintSStrUsingAnonymousMethod(int number);
namespace AnonymousMethodDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            PrintSStrUsingAnonymousMethod printString = delegate(int x)
           {
               Console.WriteLine("Anonymous method: {0}", x);
           };

            printString(2);

            Console.ReadKey();
        }
    }
}

Output

output1.PNG

Usage of delegate and anonymous method: We will discuss with the following example. Here we created a class Template Employee. And in this class there is a method to Promote the employees.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _4_use_of_delegate
{
   class Program
   {
       static void Main(string[] args)
       {
           List<Employee> employees = new List<Employee>();
           employees.Add(new Employee {Id = 1, Name = "Mahmud", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 2, Name = "Jamal", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 3, Name = "Kamal", Salary = 20000, Experience = 3 });
           employees.Add(new Employee { Id = 4, Name = "Jon", Salary = 10000, Experience = 3 });
           Employee employee = new Employee();
           employee.PromoteEmployee(employees);
           Console.ReadKey();
       }
   }
   class Employee
   {
       public int Id { get; set; }
       public string Name { get; set; }
       public int Salary { get; set; }
       public int Experience { get; set; }
       public void PromoteEmployee(List<Employee> employees)
       {
           foreach (Employee employee in employees)
           {
               if(employee.Experience >= 2)
               Console.WriteLine(employee.Name+ " is promoted");
           }
       }
   }
}

Here the employee Templete class is not re-usuable. Because the company can change it’s logic to promote employee, like as it can promote employee based on salary. So to make the employee class template reusable the logic to promote employee should be separated.

To do this we will create a delegate to point a method for this logic to promote employee and than pass this delegate instance to the promote employee method in the Employee class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Previous example was not reusuable. To make this reusable, we have to use delegate.
namespace _5_delegate_usage
{
   class Program
   {
       static void Main(string[] args)
       {
           List<Employee> employees = new List<Employee>();
           employees.Add(new Employee { Id = 1, Name = "Mahmud", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 2, Name = "Jamal", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 3, Name = "Kamal", Salary = 20000, Experience = 3 });
           employees.Add(new Employee { Id = 4, Name = "Jon", Salary = 10000, Experience = 3 });
           IsPromotable isPromotable = new IsPromotable(Promote);
           Employee employee = new Employee();
           employee.PromoteEmployee(employees, isPromotable);
           Console.ReadKey();
       }
       public static bool Promote(Employee employee)
       {
           if (employee.Experience >= 2)
               return true;
           else
               return false;
       }
   }
   delegate bool IsPromotable(Employee emp);
   class Employee
   {
       public int Id { get; set; }
       public string Name { get; set; }
       public int Salary { get; set; }
       public int Experience { get; set; }
       public void PromoteEmployee(List<Employee> employees, IsPromotable IsEligibleToPromote)
       {
           foreach (Employee employee in employees)
           {
               if (IsEligibleToPromote(employee))
                   Console.WriteLine(employee.Name + " is promoted");
           }
       }
   }
}

But with the use of lambda expression, we don’t have to instantiate the created delegate explicitly and we don’t have to create the method for it explicitly like as follows

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _6_delegate_improvement_to_the_previous_codes
{
   class Program
   {
       static void Main(string[] args)
       {
           List<Employee> employees = new List<Employee>();
           employees.Add(new Employee { Id = 1, Name = "Mahmud", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 2, Name = "Jamal", Salary = 10000, Experience = 1 });
           employees.Add(new Employee { Id = 3, Name = "Kamal", Salary = 20000, Experience = 3 });
           employees.Add(new Employee { Id = 4, Name = "Jon", Salary = 10000, Experience = 3 });
           Employee employee = new Employee();
           employee.PromoteEmployee(employees, emp => emp.Experience > 2);
           Console.ReadKey();
       }
   }
   delegate bool IsPromotable(Employee emp);
   class Employee
   {
       public int Id { get; set; }
       public string Name { get; set; }
       public int Salary { get; set; }
       public int Experience { get; set; }
       public void PromoteEmployee(List<Employee> employees, IsPromotable IsEligibleToPromote)
       {
           foreach (Employee employee in employees)
           {
               if (IsEligibleToPromote(employee))
                   Console.WriteLine(employee.Name + " is promoted");
           }
       }
   }
}

Here in the run time this lambda expression created the delegate, created the anonymous method, and passes to the class template method.

Sample source code for this post will be found at: https://github.com/mdmahmudurrahman/advanced-c-sharp