Anonymous functions and Lambda Expressions
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 article 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 does not have a name while declaration. Functions doesn’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.
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.
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
As we can see in the above figure, CLR has generated a function on its own which takes no parameter and return 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 shown below.
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 do use anonymous functions. In this part of the article I would like to cover a couple of scenarios where we can use anonymous functions.
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 perfect scenario for the click events of a button or for any control event. Please have a look at the scenario as shown below
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.
One of the unique feature of the anonymous functions is that we can use them even without the parameter decleration, even if the delegate is expecting some parameter. This can be useful in declaring events with a default empty handleras shown in the code below :
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 ,
public delegate int MyDelegate(int i);
We can assign a lambda expression and use this delegate as shown below:
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 have compatibility with MyDelegate.
Lambda expression can be used as a statement block instead of expression. In that case the above expression would be as following.
x => { return x * x; };
Lambda expression are used most commonly with the Func and Action delegates which I have discussed in one of my article, that is the reason you will find our earlier examples in the following form.
Func 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
Func 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 follow.
Func 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
private static void NewMethod()
{
int outerVar = 5;
Func 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
private static void NewMethod()
{
int outerVar = 5;
Func sqr = (int x) => x * outerVar;
outerVar = 10;
Console.WriteLine(sqr(5));// prints 50
}
Interesting Finding with Anonymous Methods
Suppose I have declared and Action delegate which takes one parameter. If we have to assign a lambda expression we have to specify the parameter. But that is not the case with anonymous method as shown in the below code.
Func actionDel = (x) => {
return x * 5;
};
Func actionDel = delegate {
return 5;
};
Capturing Iteration Variables
While completing the article I want to cover one more topic i.e. how the lambda expression are used to capture the iteration variables. When we declare an iteration variables 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
private static void MyMethod()
{
Func[] calc = new Func[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.
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 example demonstrating the use of lambda expression with ienumerable types
Where with lambda expression
private static void WhereWithLambda()
{
var names = new string[] { "Vikram", "Tarun", "Tom" };
IEnumerable 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"
}
}
Order with lambda expression
private static void OrderBy()
{
var numbers = new int[] { 1, 5, 2, 4, 3 };
IEnumerable ordered = numbers.OrderBy(i => i);
foreach (var number in ordered)
{
Console.Write(number); // 1, 2, 3, 4, 5
}
}
we have tried to cover about all the scenarios of the anonymous functions and lamba expression in this article. Please let us know your thoughts about this blog.
Source: dotnetforall
Comentarios