Delegates, Anonymous Method, And Lambda Expression In C#

Introduction

In C# and.NET, many developers struggle to build a conceptual understanding of delegates. In my team, during presentations, many people ask to discuss delegate. Once my senior at the Pune office said that when C# comes to delegates, it looks like a new programming language. Delegates can be compared to function pointers in C++ but they have many other concepts based on it. In this article, I will talk about what a delegate is and how you can extend its concept in the world of C# and .NET.

Background

Delegates are heavily used in Events, LINQ, .NET v 3.5 onwards, extension methods, and ASP.NET MVC etc. I will give you a very comprehensive explanation about delegates that is based on etymologies, like Anonymous Method and Lambda Expression. Actually, there are a lot of other things that can be discussed pertaining to delegate but that will be a separate discussion and I shall discuss that part possibly another time. In this article, you will get knowledge about three major concepts very easily.

  • Delegates have been a part of C# since version 1.0 was released. A delegate holds reference to a method. Delegates can be defined in two types : Singlecast and Multicast (Both types are discussed below in code).

  • Anonymous Method is an inline code that can be used wherever a delegate type is expected. Microsoft introduced Anonymous Methods in C# 2.0 somewhere around 2003.

  • Lambda expression is an anonymous method that you can use to create delegates or expression tree types. Microsoft introduced Lambda Expression in C# 3.0 sometime in 2007. Most of the time, anonymous methods are confused with lambda expression by many developers. I have discussed this in detail here. You know that there is one case in which an anonymous method provides functionality not found in lambda expressions, as anonymous methods enable you to omit the parameter(s).

Using Code 

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         public void CallerOne() {  
  6.             Console.WriteLine("This is Caller One function...");  
  7.         }  
  8.         static void Main() {  
  9.             //Create object of the class and give it an instance  
  10.             Program p = new Program();  
  11.             //Crete the object of delegate and note that you have to pass the method as parameter  
  12.             MyDelegate myDelegate = new MyDelegate(p.CallerOne);  
  13.             myDelegate();  
  14.         }  
  15.     }  
  16. }   

You can see that I have a delegate named MyDelegate and as you know, it can hold a reference to a Method. So, MyDelegate holds a reference to a Method CallerOne(). Know that you can also execute method with myDelegate.Invoke(); instead of calling delegate object myDelegate();. This definition will remain similar in the following code too. One more point to note - Here, look at the return type and parameters. Delegate and Method signature must be same to implement it. Let's go next to copy and paste the below code in your console application's Program.cs.

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         public void CallerOne() {  
  6.             Console.WriteLine("This is Caller One function...");  
  7.         }  
  8.         public void CallerTwo() {  
  9.             Console.WriteLine("This is Caller Two function...");  
  10.         }  
  11.         static void Main() {  
  12.             //Create object of the class and give it an instance  
  13.             Program p = new Program();  
  14.             //Crete the object of delegate and note that you have to pass the method as parameter  
  15.             MyDelegate myDelegate = new MyDelegate(p.CallerOne);  
  16.             //Crete the object of delegate and note that you have to pass the method as parameter  
  17.             MyDelegate myDelegate1 = new MyDelegate(p.CallerTwo);  
  18.             myDelegate();  
  19.             myDelegate1();  
  20.         }  
  21.     }  
  22. }   

In the above step, there is another object of Delegate named myDelegate1 but it does the similar job as in first code. So, we have implemented two objects of the same delegate. Let's next copy and paste the below code in you console application's Program.cs.

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         public void CallerOne() {  
  6.             Console.WriteLine("This is Caller One function...");  
  7.         }  
  8.         public void CallerTwo() {  
  9.             Console.WriteLine("This is Caller Two function...");  
  10.         }  
  11.         public static void CallerThree() {  
  12.             Console.WriteLine("This is Caller Three function...");  
  13.         }  
  14.         static void Main() {  
  15.             //Create object of the class and give it an instance  
  16.             Program p = new Program();  
  17.             //Crete the object of delegate and note that you have to pass the method as parameter  
  18.             MyDelegate myDelegate = new MyDelegate(p.CallerOne);  
  19.             //Crete the object of delegate and note that you have to pass the method as parameter  
  20.             MyDelegate myDelegate1 = new MyDelegate(p.CallerTwo);  
  21.             //Crete the object of delegate and note that you have to pass the method as parameter  
  22.             MyDelegate myDelegate2 = new MyDelegate(CallerThree);  
  23.             myDelegate();  
  24.             myDelegate1();  
  25.             myDelegate2();  
  26.         }  
  27.     }  
  28. }   

Think about the above code! Why should I not allocate the memory to the method at compile time, instead of calling member function/ method using class object? So, I marked CallerThree as static method.

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         public void CallerOne() {  
  6.             Console.WriteLine("This is Caller One function...");  
  7.         }  
  8.         public void CallerTwo() {  
  9.             Console.WriteLine("This is Caller Two function...");  
  10.         }  
  11.         public static void CallerThree() {  
  12.             Console.WriteLine("This is Caller Three function...");  
  13.         }  
  14.         static void Main() {  
  15.             //Create object of the class and give it an instance  
  16.             Program p = new Program();  
  17.             //Crete the object of delegate and note that you have to pass the method as parameter. This is Single Cast  
  18.             MyDelegate myDelegate = new MyDelegate(p.CallerOne);  
  19.             //Crete the object of delegate and note that you have to pass the method as parameter. This is Single Cast  
  20.             MyDelegate myDelegate1 = new MyDelegate(p.CallerTwo);  
  21.             //Crete the object of delegate and note that you have to pass the method as parameter. This is Single Cast  
  22.             MyDelegate myDelegate2 = new MyDelegate(CallerThree);  
  23.             myDelegate();  
  24.             myDelegate1();  
  25.             myDelegate2();  
  26.             //This Idea is Called Multi Cast  
  27.             MyDelegate MyDelegate_MultiCast_Idea = myDelegate + myDelegate1 + myDelegate2;  
  28.             MyDelegate_MultiCast_Idea();  
  29.         }  
  30.     }  
  31. }   
Look at the code above. MyDelegate_MultiCast_Idea object is the sum of all previous objects. This is called Multi-Casting in delegates. At this point, you shall be clear that first, second, and third code from starting article will have 1, 2, 3 Singlecast delegates respectively, for each of the individual methods.

Now, pay attention! By the requirement to implement a delegate, we have to have a method defined but that is complicated. If I take this idea to 3 tier architecture that means changing Presentation Layer has to be reflected in Business Layer and Data Layer. In short, changes will have impact! So, think about something where we can write the method itself and pass its reference. Microsoft did this job with C# 2.0 by introducing Anonymous Methods.

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         static void Main() {  
  6.             //I have passed full method body within delegate instance and more important this method don't have a name  
  7.             MyDelegate myDelegate = new MyDelegate(delegate() {  
  8.                 Console.WriteLine("This is Caller One function...");  
  9.             });  
  10.             MyDelegate myDelegate1 = new MyDelegate(delegate() {  
  11.                 Console.WriteLine("This is Caller Two function...");  
  12.             });  
  13.             MyDelegate myDelegate2 = new MyDelegate(delegate() {  
  14.                 Console.WriteLine("This is Caller Three function...");  
  15.             });  
  16.             myDelegate();  
  17.             myDelegate1();  
  18.             myDelegate2();  
  19.         }  
  20.     }  
  21. }   
Absolutely clean and clear code! Delegate holds reference to a method but here delegate holds the method itself.. so what is the name of the method? No name!! That is why it is called Anonymous Method!
 
As mentioned earlier in the article, delegate's signature must match with the method it takes in reference and vice versa. There is one case in which an anonymous method provides functionality not found in Lambda Expression. Anonymous methods enables you to omit the parameter(s). This feature is very important in both ways. It can be used making system more flexible by using Anonymous Method and or more of strongly typed using Lambda Expression. This comparison is given after the code. 
  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate();  
  4.     class Program {  
  5.         static void Main() {  
  6.             //Here '=>' thing work to implement Labda Expression. It can be further dicsussed but I will discuss this in future article.  
  7.             MyDelegate myDelegate = new MyDelegate(() => {  
  8.                 Console.WriteLine("This is Caller One function...");  
  9.             });  
  10.             myDelegate();  
  11.         }  
  12.     }  
  13. }   
Let's have a comparison on Anonymous Method vs Lambda Expression. This example will give at least two ideas. The first one is working with parameterized delegates and the second one is the comparison between Anonymous Method and Lambda Expression. 
  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate(int num);  
  4.     class Program {  
  5.         static void Main() {  
  6.             MyDelegate myDelegate = new MyDelegate(delegate {  
  7.                 Console.WriteLine("This is Caller One function...");  
  8.             });  
  9.             myDelegate(211);  
  10.         }  
  11.     }  
  12. }   

You can take note that you have passed parameter num value 211 but Anonymous Method can omit it and program is executed. Now, with the same delegate, look at the below code which uses Lambda Expression. It will throw compile time error because you will have to pass parameter in method body to compile and execute. How to pass the parameter in this? I leave this very simple job up to you and you have to post your answer in the comments.

  1. using System;  
  2. namespace DAL {  
  3.     public delegate void MyDelegate(int num);  
  4.     class Program {  
  5.         static void Main() {  
  6.             MyDelegate myDelegate = new MyDelegate(delegate {  
  7.                 Console.WriteLine("This is Caller One function...");  
  8.             });  
  9.             myDelegate(211);  
  10.         }  
  11.     }  
  12. }   

Hint - Pass your parameter (here) => Method Body

Conclusion

I tried my best to deliver this great idea to you. Hope you enjoyed! Further, I will talk about Action, Predicate, and Func, probably by next week sometime. You can subscribe to me for posts by going to my profile or joining my small WhatApp group for knowledge sharing here.

Thanks ! Happy Coding..!