Delegate, Anonymous Method and Lamda Expression in C# (Part 2/2)


What are anonymous method?
 Anonymous methods are similar to normal methods but they do not have a name and can be directly assigned to a delegate. These methods are not reusable components that is why they don’t have a method name. They make the code simple and more readable. One reason why we need an anonymous method is that often times a method is created so that it can be assigned to the delegate instance and called through the delegate reference.
How to create an anonymous method?
Anonymous methods are methods without a name which are directly created and assigned to a delegate instance. See code below where displayTime is an instance of delegate Display that accepts no parameter and has voice return type.
Display displayTime = delegate(){
      Console.WriteLine(DateTime.Now.ToString("dd/mm/yyyy"));
};
delegate() means that this anonymous method takes no parameter and {} defines the block of statements to be run when this anonymous method is called via delegate’s instance. In this example we only have console.write statement which prints the current date.
How does compiler know that the anonymous method agrees with the method signature and return type specified by the delegate? Well the compiler looks into delegate definition and compares the parameter list and return type with that specified by the anonymous method. If it has same parameter/s and return type as in definition of delegate, then the anonymous method compiles successfully.
Example 1: Anonymous method (no parameter & void return type)
The code below shows how to create an anonymous method that can be assigned to delegate instance which accepts no argument/parameter and whose return type is void.
using System;
namespace HelloWorld
{

public delegate void Display();
public class Program
    {
       
        static void Main(string[] args)
        {
Display displayTime = delegate (){
      Console.WriteLine(DateTime.Now.ToString("dd/mm/yyyy"));
};
              displayTime();
              Console.ReadKey();
        }
          }
}
Here, first we created a delegate named Display that can hold reference to the method which takes no parameter and has a void return type. Then in the main method, we created an instance of delegate named displayTime and assigned it an anonymous method. Next we called the method referred by delegate instance that is the anonymous method which shows the current date.

Example 2: Anonymous method (two parameter & a return type)
using System;
namespace HelloWorld
{

    public delegate string Print(string message, int noOfTimes);
    class Program
    {
       
        static void Main(string[] args)
        {
                    Print printMessage = delegate(string s, int noOfTimes) {
                     string msg="";
                     for (int i = 0; i < noOfTimes; i++)
                     {
                            msg += s + "\n";
                     }
                     return msg;
                    };
                    string text = printMessage("Write this five times", 5);
              Console.WriteLine(text);
              Console.ReadKey();
        }
          }
}

Here we can see in the above code that when we have parameter we simply write them within the enclosed parenthesis of delegate (which in this case is delegate (string s, int noOfTimes)  ) and after writing the method’s logic we end it with a return statement (which in this case is return msg).

Outer Variable in anonymous methods:
Just before closing this topic, I want to discuss outer variable because then can cause trouble if ignored. Outer variables are those variable whose scope (scope under which they are declared) includes an anonymous method. When this happens, that variable is accessible by the anonymous method and it does not go out of scope until the delegate instance is collected by garbage collector. Let’s see an example of outer variable.



using System;
namespace HelloWorld
{
    public delegate void CountToFive();


    class Program
    {
        public static CountToFive Method_Using_OV() {
            int countStart = 1; //Captured Variable
            CountToFive counting = delegate ()
            {
                int countEnd = countStart + 4;
                for (countStart=1;  countStart<= countEnd; countStart++)
                {
                    Console.WriteLine("Count = "+countStart +"\n");
                }
               
            };
            return counting;
        }
       
        static void Main(string[] args)
        {
            CountToFive ov = Method_Using_OV();
            ov();
            Console.WriteLine( "Variable countStart is captured by the anonymous method"
            );
            Console.WriteLine();
     ov();
        }

       }
}
OUTPUT:
count = 1
count = 2 
coutn = 3
count = 4
count = 5

Varuable countStart is captured by anonymous method

count = 1
count = 2 
count = 3
count = 4
count = 5
count = 6
count = 7 
count = 8

count = 9
count = 10



In the example above, we created a delegate that can refer to method which does not have a return type and takes no argument. After that, we created a method which returns a delegate instance which holds a reference to an anonymous method. The anonymous method uses a local variable countStart which is accessible through anonymous method as it is in its scope. This variable is captured until the delegate instance is subject to garbage collector.

After the first call to the anonymous method from the delegate, the countStart value becomes 5. When the anonymous method is called second time, countStart still exist and value of it is still 5 which is assigned to countEnd  and countEnd becomes 10. Similarly, if we call it third time countEnd will become 15 because countStart would be 10 at that time.    

Though the concept of captured variable looks strange at first but if you think of the logic behind it, then it would look obvious.

Lamda Expression

The lamda expression is another handsome way of creating anonymous function. Because of its shorthand approach to create an anonymous method, it makes the program simple and easy to understand. The lamda expression is mostly used with LINQ but it can also be used with delegates and events.
 The lamda expression has a little different syntax. Let’s see an example
Example 1: Lamda Expression for delegate referring to method with no parameter & void return type
using System;
namespace HelloWorld
{

    public delegate void DisplayHelloWorld();

    class Program
    {
       
        static void Main(string[] args)
        {
              // Lamda Expression
                    DisplayHelloWorld disp = () => Console.WriteLine("Hello World!");
              disp();
              Console.ReadKey();
        }
          }
}
OUTPUT:
Hello World!

In the above code, see how delegate instance is given an anonymous method through lamda expression. This is a shorthand as compare to anonymous method. After the assignment operator = we have empty parenthesis () which shows that this delegate is referring to a method that does not take any parameter. After that, we have => operator known as “becomes” after this operator we define the body of the method which in this case is Console.WriteLine("Hello World"); . Since it’s a single statement, we don’t need curly brackets {}. If it were more than a single statement, we would place curly brackets after => operator and it would be called Statement Lamda rather than Lamda Expression.  

So as you saw it is an easy way to create anonymous method. Lets see another example, where the delegate requires method with some parameter.
Example 2: Lamda Expression for delegate referring to method with two parameters & a return type
using System;
namespace HelloWorld
{

          public delegate bool CompNo(decimal balance, decimal price);
   class Program
   {
       
        static void Main(string[] args)
        {
                    CompNo canBuy = (b, p) => b - p >= 0;
                    decimal balance = 10m, itemPrice=9m;
            
                    if (canBuy(balance,itemPrice))
                           Console.WriteLine("Yes, you have sufficient balance to buy item.");
                    else
                    Console.WriteLine("You have insufficient balance to buy item");
              Console.ReadKey();
        }
          }
}
OUTPUT:

Yes, you have sufficient balance to buy item.

Well here the delegate CompNo refers to method with two input parameter of type int and return a bool. The lamda expression defines an anonymous method in which if the value of first parameter is greater than the second parameter then it returns true else returns false. See how this function is so simply written and easy to understand. You might be thinking that we did not specify the types of parameter in lamda expression (b, p), well this is the beauty of lamda expression that we don’t need to specify types in input parameters because the compiler will do this for us by looking into the delegate definition. We are also not required to write a return statement instead the compiler understand that the expression is the actual value which is return.
Note: in lamda expression return statement is not allowed. While in statement lamda return statement is allowed. See example below.   

Example 3: Lamda Expression for delegate referring to method with two parameters & a return type
using System;
namespace HelloWorld
{

          public delegate int Cal (int x, int y);
   class Program
   {
       
        static void Main(string[] args)
        {
            
Cal sum = (a,b) =>  a + b; //Lamda Expression
                    Cal sub = (a, b) => { return a - b; };//Statement Lamda

                    int x = sum(10, 10);
                    int y = sub (20, 9);

                    Console.WriteLine(x);
                    Console.WriteLine();
                    Console.WriteLine(y);
              Console.ReadKey();
        }
          }
}
OUTPUT:
20

11

The example above declares a delegate named Cal that refers to a method whose return type is int and which accepts two int parameters. The instance sum of delegate Cal, assigns the delegate instance a method which computes the sum of input parameter using lamda expression. While another instance of delegate Cal, subtracts the second parameter from the first parameter using statement lamda.

Comments

Popular posts from this blog

Implementing Basic and JWT Token authentication with C# .NET

.NET Core 3 officially comes to Windows IoT Core

Setting up Free Custom Domain on Microsoft Azure Web App Service

Setting up CI and CD pipeline in Azure DevOps for ASP.NET Core and Azure Web Apps

Microsoft Azure DevOps : A Complete CI & CD solution in the cloud

Securing Powershell Scripts with Code-Signing Certificate

Understanding Powershell ExecutionPolicy and securing Powershell CmdLets/Scripts with Code-Signing Certificate

Microsoft Azure Blob Storage - Managing Blobs and storage containers from C#

Xamrin Android Push Notification using Firebase Cloud Messaging

Fundamental of Powershell Scripting