Delegates are one of the important concepts of C# and a bit difficult to digest for beginners. This article explains how delegates, anonymous functions and lambdas are related and how lambdas have evolved from delegates. Basically all these are the same concepts with a change in syntax only, but the change is so refined that the code of writing delegates has been changed to writing a lambda expression that is a one line code. I will explain the things step by step and will first start with delegates.
Delegates
Delegates can be defined as function pointers (as in C). In simple words we can say that they allow passing a function as a parameter to another function. The benefits of delegates can be best understood with an example.
Suppose we have a class, Student, that contains data and functions that sort data based upon some conditions. If in the future we want to add another condition for sorting the data then we need to change our code and must add another method. But if we use delegates then we need not change our code because our code will become dynamic by using delegates. To explain that I will create a class Student as in the following:
- public class Student
- {
- public int Id { get; set; }
- public string Name { get; set; }
- public int Marks { get; set; }
- }
Now I will create a delegate that returns a bool and accepts an object of type Student.
- public delegate bool IfStudentGotExtinction(Student ob);
After that I will create a function that accepts a parameter of type
IfStudentGotExtinction. The parameter acts like a container in which we can pass a function for sorting students.
- public void ShowExtinctionStudent(IfStudentGotExtinction studentExtinction)
- {
- foreach (Student student in employeeList)
- {
- if (studentExtinction(student))
- {
- Console.WriteLine(student.Name);
- }
- }
- }
Now I will create a function (whose signature matches the signature of the delegate) that will return all the students whose marks are above 80 and I will pass the preceding function to the delegate that I will pass to the preceding method.
- public static bool CheckExtinction(Student student)
- {
- if (student.Marks > 80)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
Now I will create an instance of the delegate (IfStudentGotExtinction) and pass a function in that.
- Sample ob = new Sample();
- IfStudentGotExtinction studentExtinction = new IfStudentGotExtinction(CheckExtinction);
- ob.SortStudent(studentExtinction);
In this code we have moved the conditions out of the Student class for sorting records. The user can write their own conditions and pass them in the function. If we want another sorting condition we can create another function and pass that to our delegate. That makes our code dynamic which is an advantage of using delegates.
The code above might look a bit odd since we are creating a separate method every time we want to sort the records and pass that to the delegate. For a clean solution and to make the code above flexible we have anonymous methods and lambdas.
Anonymous Functions
Anonymous functions were introduced in C# 2.0 for the purpose of providing more flexibility to the code. An anonymous function is a function with no name. We can create them with the delegate keyword and add multiple statements to that. We can pass an anonymous function to the delegate. Instead of creating a separate function and then assigning that to a delegate we can directly write a function body as a parameter while calling the Sort method of the Student class.
- ob.SortStudent(delegate(Student student)
- {
- if (student.Marks > 50)
- {
- return true;
- }
- return false;
- });
The code above looks much better and clean compared to the above traditional method of creating a function and assigning a delegate. But we can see the power of using delegates as our class has become dynamic and we can sort our data depending on our needs.
Lambdas Expression
For making the code look more concise and clean Microsoft has introduced lambdas in C# 3.0. A lambda expression is nothing but an anonymous function with concise syntax. In an anonymous function we are required to declare the type of parameter that we will pass but a lambdas type of parameter is inferred from the delegate.
For example if we are using an anonymous function and we know that our delegate will accept a parameter of type Student then in the anonymous function we again specify the type of parameter as shown below but in a lambda this redundancy is removed.
An example of writing a lambda expression is given below:
- ob.SortStudent(x => x.Marks < 50);
As we can see the delegate keyword and braces are removed in lambdas. Instead of that we just write a condition directly where x (or any name) is a parameter of type Student(which is inferred by the compiler in lambdas) and => is the operator that indicates the start of the body of function. Then we will write a condition that is returning bool. If we have multiple conditions then we can write it using the && operator. So we can see how the changes have been done from working with delegates to lambdas with the base of delegates remaining the same and the major change is in the syntax only.
Lambdas are generally preferred when we don't have a method body. So we should use lambdas when we have short conditions and we can use anonymous functions if we have multiple lines of code.
You can refer to the code attached.