.NET Articles

c# delegates and lambda expressions


Delegate

Delegate is a function pointer. Declare delegate with same signature as method.

Sample Code

public delegate int Calculate(int a, int b);
class Program
    {
        static void Main(string[] args)
        {
            Calculate _calcSum = new Calculate(Sum);
            Console.WriteLine("Sum : {0}",_calcSum(3,2));
            Console.Read();
        }
        public static int Sum(int a ,int b)
        {
            return a + b;
        }
    }

Output:

Sum : 5

Create another calculate method for multiplication similar to above “Sum” method but it accepts type double. As method signatures are different we have to create one more delegate “Calculate_double” with double type as shown below.

public delegate int Calculate(int a, int b);
public delegate double Calculate_double(double a, double b);

class Program
{
    static void Main(string[] args)
    {
        Calculate _calcSum = new Calculate(Sum);
        Console.WriteLine("Sum : {0}",_calcSum(3,2));

        Calculate_double _calcSum_double = new Calculate_double(Multiply);
        Console.WriteLine("Multiply : {0}", _calcSum_double(2.5, 2.5));

        Console.Read();
    }
    public static int Sum(int a ,int b)
    {
        return a + b;
    }
    public static double Multiply(double a, double b)
    {
        return a * b;
    }
}

                     

Output:

Sum : 5

Multiply : 6.25

We have used two delegates for sum and multiply functions because of different input types. We can simplify this code by using generic delegate that is one generic delegate can be used for calling two methods as shown below.

public delegate TResult Calculate<out TResult, in T1, in T2>(T1 a,T2 b );
class Program
{
    static void Main(string[] args)
    {

        Calculate<int, int, int> _calSumInt = new Calculate<int, int, int>(Sum);
        Console.WriteLine("Sum(generic type int) : {0}",_calSumInt(3,2));


        Calculate<double, double, double> _calSumDouble = new Calculate<double, double, double>(Multiply);

        Console.WriteLine("Multiply(generic type double) : {0}", _calSumDouble(7.5, 7.5));
          
            Console.Read();
    }
    public static int Sum(int a ,int b)
    {
        return a + b;
    }
    public static double Multiply(double a, double b)
    {
        return a * b;
    }

}
                     

Output:

Sum(generic type int) : 5

Multiply(generic type double) : 56.25

After declaring generic type then we get generic delegate types as shown below

Generic Delegate

Note:

public delegate TResult Calculate<out TResult, in T1, i T2>(T1 a,T2 b );

In generic delegate, we have to mention keywords “in” and “out” as variable types input and output (as shown in Calculate) but generic method it is not required.

For generic method, keywords “in” and “out” are not required. As shown below.

public static TResult Calculate<TResult,T1,T2>(T1 a,T2 b)

Let us now do the same calculations using delegate but using system delegates.

Microsoft has provided inbuilt delegates to reduce the overhead of creating our own delegate every time. See below code how system delegate “Func” has been replaced our manual delegate “Calculate”.

class Program
{
    static void Main(string[] args)
    {

        Func<int, int, int> _calSumInt = new Func<int, int, int>(Sum);
        Console.WriteLine("Sum(generic type int) : {0}",_calSumInt(3,2));

        Func<double, double, double> _calSumDouble = new Func<double, double, double>(Multiply);
        Console.WriteLine("Multiply(generic type double) : {0}", _calSumDouble(7.5, 7.5));
          
            Console.Read();
    }
    public static int Sum(int a ,int b)
    {
        return a + b;
    }
    public static double Multiply(double a, double b)
    {
        return a * b;
    }

}
                     

There are 3 following system delegates

1)Func: This is very useful delegate and we can use it frequently. This has 17 overload type argument delegates and each has return type argument as shown below.

Func System Delegates

2)Action: It is similar to system delegate “Func” with 16 overload type arguments but none of them has return type.

3)Predicate: This delegate accepts only one type input parameter and returns Boolean type.

Lambda Expression

Let me summarize what we have learned so far.

1)Created 2 delegates for Sum and Multiplication functions.

2) Then replaced 2 delegates with one generic delegate for Sum and Multiplication functions.

3) We have further simplified the code by replacing generic delegate with system delegate “Func”.

The question now is can we simplify the code further for Sum and Multiply? Yes it is possible with Lambda expression. We can completely remove Sum and Multiplications functions using lambda expression as shown below.

class Program
{
    static void Main(string[] args)
    {
        Func<int, int, int> _calSum = (a, b) => a + b;
        Console.WriteLine("Sum : {0}", _calSum(3, 2));

        Func<double, double, double> _calMultiply = (a, b) => a * b;
        Console.WriteLine("Multiply : {0}", _calMultiply(12, 12));

        Console.Read();
    }
}

                     

Output:

Sum : 5

Multiply : 1.44

What a simplified code compare to above methods! This is the amazing feature of Lambda expression.

Lambda expression is a great feature of c#. Let us take a simple scenario that you have a collection of Employees object. Assume you need a three filter criterias they are 1)Employees whose name starts with “V” 2)Employees whose name starts with “N” 3)Employees whose length of name is greater than 5 characters. Without using lambda expression, we have to write 3 methods before you use and we never know what kind of filter would require on employee collection in future and it is not possible to write all possible filter methods in advance. These three kinds of methods can be written using lambda expression as method so anytime you can apply whatever filter criteria you want in one line lambda expression code as a method.

Let us write a filter method “Filter” on object collection to perform different search criteria.

using System;
using System.Collections.Generic;

namespace GenericsDelegatesLambda
{
class Program
{
    static void Main(string[] args)
    {
        List<Emp> _emps = new List<Emp>();
        _emps.Add(new Emp() { Name = "Chris", FatherName = "Gopal" });
        _emps.Add(new Emp() { Name = "Vijay Mohan", FatherName = "Rama" });
        _emps.Add(new Emp() { Name = "Vyasa", FatherName = "Sunil" });
        var results = _emps.Filter<Emp>(a => a.Name.StartsWith("V") && a.Name.Length > 5 && a.Name.EndsWith("n"));
        //You can write code as below as well
        //var results = _emps.Filter(a => a.Name.StartsWith("V") && a.Name.Length > 5 && a.Name.EndsWith("n"));

        foreach (var item in results)
        {
            Console.WriteLine(item.Name);
        }
        Console.ReadLine();
    }                            
}

public class Emp
{
    public string Name { get; set; }
    public string FatherName { get; set; }
}

public static class MyExtensions
{

    public static IEnumerable<T> Filter<T>(this IEnumerable<T> Collection, Func<T,bool> filter)
    {            
        foreach (var item in Collection)
        {
                
            if (filter(item))
                yield return item;
        }
    }
}    
}

Output:

Vijay Mohan

“Filter” method is an extension method on collection(IEnumerable). It accepts the system defined delegate “Func<T,bool>” as shown below. “Func” delegate has input as object and returns Boolean.

public delegate TResult Func<in T, out TResult>(T arg);

Note: System delegate “Func” has 17 overload method signatures(discussed above)

“Filter” method that we wrote works exactly same as “Where” extension method(shown below). My intention is to make you understand how system defined “Where” method is working.

var results = _emps.Where(a => a.Name.StartsWith("V") && a.Name.Length > 5 && a.Name.EndsWith("n"));

Expression Tree:

If you pass delegate as type argument to class “Expression” then it is called as expression tree. Expression Tree represents the lambda expression as data structure in the form of expression tree. You understand better if you see below screenshots.

class Program
{
    public static void Main(string[] args)
    {
        Func<int, int, int> _CalcMult = (a, b) => a * b;
        Console.WriteLine("Using Lambda expression result {0}",_CalcMult(5,5));
        Expression<Func<int, int, int>> _expressionMult = (a, b) => a * b;
        Func<int, int, int> _mult= _expressionMult.Compile();                                   
        Console.WriteLine("Using Expression Tree result {0}", _mult(4, 4));
        Console.ReadLine();
    }
}

In debug mode, lambda variable won’t show the body of lambda expression.

Example:

Delegate Debug mode

In debug mode ,you notice that the lambda expression “_CalcMulply” is not showing the logic, it is showing just signature of delegate.

If you want to see the logic of lambda expression in debug mode, Use “Expression” class as shown below.

Image

ExpressionTree Debug mode

If you further expand in debug mode you can see Parameter Count,Body and return type as shown in below screenshot.

Image

Expression Tree Debug mode

To make use of Expression tree, following two things are required.

1)Pass delegate type to “Expression“ class as type argument

2)Use .compile() method on Expression instance

Again moving back to delegate, one of the greatest feature of delegate is events. You cannot create an event without delegate. Let us take this scenario. You are writing one class Employee and this is going to use by other organization and you should provide a feature to inject execution of their own method when executing your class Employee. This is possible through event using delegate. Please see simple example of of event here