Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Anonymous Functions and Lambda Expressions

4.47/5 (8 votes)
19 Aug 2015CPOL6 min read 14.1K  
Anonymous functions and Lambda Expressions

Introduction

As we know from my previous post of the delegates in C#, that delegates are reference type which take functions as parameters which would be in-turn executed once the delegate is invoked. In this blog, I will discuss about the anonymous functions and lambda expressions in C# which are introduced in .NET framework 2.0 and 3.0 respectively.

Anonymous Functions

I want to start this discussion with the introduction of anonymous functions in C# which have been subsequently replaced by lambda expressions in .NET 3.0. As the name suggests, these functions do not have a name during declaration. Functions don’t have a name in C# !!! Yes, these functions are directly assigned to the delegate type while initializing it, as we already know that delegates can be initialized by directly assigning a function to it as shown below:

C#
public delegate void MyDelegate();
        static void Main(string[] args)
        {
            MyDelegate inst = MyFunction;
            inst(); //prints "Delegate Invoked"

            Console.Read();
        }

        public static void MyFunction()
        {
            Console.Write("Delegate Invoked");
        }

The same thing can be achieved by using the anonymous functions as shown below:

C#
static void Main(string[] args)
        {
            MyDelegate inst = delegate() { Console.Write("Delegate Invoked using anonymous"); };
            inst(); //prints "Delegate Invoked using anonymous"

            Console.Read();
        }

What exactly happened here is that the CLR has generated a function on its own, the fact which we can confirm by having a look at the generated IL code, the snapshot of which is shown below:

Anonymous Function via CLR

Anonymous Function via CLR

As we can see in the above figure, CLR has generated a function on its own which takes no parameter and returns void, which it does intelligently at compile time after analyzing the delegate for which the function has been used.

Anonymous Function with Parameter

The case described above is not the only valid scenario for anonymous functions. Anonymous functions can also be used along with parameters as shown in the code snippet below:

C#
public delegate void MyDelegate(int x);
        static void Main(string[] args)
        {
            MyDelegate inst = delegate(int x) { Console.Write(5); };
            inst(5); //prints "5"
            Console.Read();
        }

As shown in the code snippet above, I have changed MyDelegate to accept one integer type of parameter and subsequently I have changed my anonymous function to have a single integer function.

Anonymous Function Utilization

Till now, I have described how to create the anonymous functions and use them. But why use anonymous functions? In this part of the article, I would like to cover a couple of scenarios where we can use anonymous functions.

  1. The first scenario where we can use anonymous function is to instantiate the delegate with the functions definition where we do not want the delegate instance to have multiple type of functionalities attached with it, as we can have only a single kind of functionality in a single function. This would be a perfect scenario for the click events of a button or for any control event. Please have a look at the scenario as shown below:
    C#
    button1.Click += delegate(object sender, RoutedEventArgs e) { MessageBox.Show("Button 1 Clicked"); };

    The above code will display a message box whenever the button is clicked.

  2. One of the unique features of the anonymous functions is that we can use them even without the parameter declaration, even if the delegate is expecting some parameter. This can be useful in declaring events with a default empty handler as shown in the code below:
    C#
    public class MyClass
            {
                public delegate void MyDelegate(int x);
                public event MyDelegate mydelegateEvent;
    
                public MyClass()
                {
                    mydelegateEvent += delegate { };
                }
     }

    Wherever we have to use mydelegateEvent of the class MyClass, there would not be any need to check the mydelegateEvent against null check before firing the event.

Lambda Expressions

As per MSDN, a lambda expression is an anonymous function, that we can use to create delegates or expression tree types. What we can infer from this statement is that a lambda expression is an unnamed method which can be replaced with a delegate instance.

Now suppose we have a delegate as shown below:

C#
public delegate int MyDelegate(int i);

We can assign a lambda expression and use this delegate as shown below:

C#
MyDelegate del = x =>  x * x;
                    Console.WriteLine(del(5)); //prints 25

The syntax for a lambda expression is as shown below:

(parameters) => expression or statement block;

Each parameter of the lambda expression is analogous to a delegate parameter and the type of expression is equivalent to the return type of delegate.

In the above example, x corresponds to parameter i, and the expression x * x corresponds to the return type int, that is why our lambda expression has compatibility with MyDelegate.

Lambda expression can be used as a statement block instead of expression. In that case, the above expression would be as follows:

C#
x => { return x * x; };

Lambda expressions are used most commonly with the Func and Action delegates which I have discussed in one of my blogs, that is the reason you will find our earlier examples in the following form.

C#
Func<int, int> sqr = x => x * x;

Specifying the Parameter Type

Though compiler can usually infer the type of the lambda parameter contextually as is the case with anonymous functions, but if that is not the case we should explicitly specify type of each parameter. Consider the following expression:

C#
Func<int, int> calc = x => x * x;

Here the compiler has used type inference that x is of type int. The other case would be to specify the type of x as follows:

C#
Func<int, int> calc = (int x) => x * x;

Can we assign lambda expression or anonymous functions to variable?

Definitely no, we cannot assign the lambda expression to a local variable as CLR determines the type of the parameters and return type of the lambda expression based on the delegate type.

Dealing with outer variable

The lambda expression and anonymous functions can be used to work on the outer variables and parameters of the methods in which it is defined as shown below:

C#
private static void NewMethod()
            {
                int outerVar = 5;
                Func<int, int> sqr = (int x) => x * outerVar;
                Console.WriteLine(sqr(5));// prints 25
            }

The outer variable referenced by the lambda expression are called captured variables and the lambda expression which works on the captured variables are known as closures.
Now the value of the outer variable is not utilized as ling as the lambda expression is not executed which I can show in the code snippet below:

C#
private static void NewMethod()
            {
                int outerVar = 5;
                Func<int, int> sqr = (int x) => x * outerVar;
                outerVar = 10;
                Console.WriteLine(sqr(5));// prints 50
            }

Capturing Iteration Variables

While completing the article, I want to cover one more topic, i.e., how the lambda expressions are used to capture the iteration variables. When we declare an iteration variable, C# treats the variable as if it has been declared outside the iteration loop.

This can be confirmed by the code snippet as shown below:

C#
private static void MyMethod()
            {
                Func<int>[] calc = new Func<int>[3];
                for (int i = 0; i < 3; i++)
                {
                    calc[i] = () => i * i;
                }

                foreach (var func in calc)
                {
                    Console.Write(func()); // always prints 4 as last value of i is 2
                }
            }

As we can see from the above code when the Func of the calc array is executed for all the three array elements the result is digit 9, as the lambda expression captures the last value from the array. In the above example, the I’s last value is persisted for the calc array.
This can be resolved by having a local variable in the initial array, as shown below:

C#
for (int i = 0; i < 3; i++)
                {
                    int temp = i;
                    calc[i] = () => temp * temp;
                }

Lambda Expression Examples With Extension Methods

.NET framework has efficiently used the lambda expression to create the extension methods for the enumerable types which can work on the data contained by these types. In the last topic of this article, I want to cover a couple of examples demonstrating the use of lambda expression with ienumerable types:

  1. Where<T> with lambda expression:
    C#
    private static void WhereWithLambda()
            {
                var names = new string[] { "Vikram", "Tarun", "Tom" };
    
                IEnumerable<string> hasVorm = names.Where(s => s.Contains('V') || s.Contains('m'));
                foreach (var item in hasVorm)
                {
                    Console.Write("\n" + item); // The result would be "Vikram" and "Tom"
                }
            }
  2. Order<T> with lambda expression:
    C#
    private static void OrderBy()
            {
                var numbers = new int[] { 1, 5, 2, 4, 3 };
                IEnumerable<int> ordered = numbers.OrderBy(i => i);
                foreach (var number in ordered)
                {
                    Console.Write(number); // 1, 2, 3, 4, 5
                }
           }

I have tried to cover about all the scenarios of the anonymous functions and lamba expression in this article. Please let me know your thoughts about this blog.

The post Anonymous functions and Lambda Expressions appeared first on Dot Net For All.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)