Summary: in this tutorial, you’ll learn about C# lambda expressions and how to use them to define anonymous functions.
Introduction to C# lambda expressions
A lambda expression is an anonymous method written in place of a delegate instance. A lambda expression is used to create an anonymous function.
A lambda expression can have one of two forms: expression lambda and statement lambda.
An expression lambda has an expression in its body:
(parameters) => expression
Code language: C# (cs)
A statement lambda has a statement block as its body:
(parameters) => { statements; }
Code language: C# (cs)
In this syntax, the =>
is called the lambda operator.
To form a lambda expression, you specify input parameters on the left side of the lambda operator and an expression or statement block on the right side.
If a lambda expression doesn’t have any input parameter, you can use an empty parentheses ()
. For example:
() => expression;
Code language: C# (cs)
If a lambda expression has exactly one parameter and the C# compiler can infer the type of the parameter, you can omit the parentheses like this:
Func<T, TResult> lambda = parameter => expression;
Code language: C# (cs)
If a lambda expression has multiple parameters, you can use a comma to separate between two parameters as follows:
(p1, p2, p3) => expression;
Code language: C# (cs)
C# lambda expression examples
The following example defines a lambda expression that returns the square of an integer:
var square = (int x) => x * x;
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
In this example, the following is a lambda expression:
(int x) => x * x;
Code language: C# (cs)
It accepts an integer and returns the square of that integer.
If you want to use the statement lambda, you need to use a return statement inside the statement block. For example:
var square = (int x) =>
{
return x * x;
};
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
Note that you can explicitly specify the return type of a lambda expression. For example, the following explicitly uses int as the return type of the lambda expression:
var square = int (int x) => x * x;
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
When the C# compiler encounters a lambda expression, it converts the lambda expression to a delegate instance. In the above example, the C# compiler converts the lambda expression to Func<int,int>
. See the following example:
Func<int,int> square = x => x * x;
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
In this example, we declare the square
as an instance of the Func<int,int>
.
Because the Func<int, int>
accepts an integer and returns an integer, we don’t need to explicitly specify the type for the input parameter of the lambda expression. Therefore, we can omit the parentheses.
Capturing outer variables
A lambda expression can reference any variables including local variables, parameters, and members that are accessible from the location where you define the lambda expression. These variables are called outer variables.
The variables referenced by a lambda expression are known as captured variables. When a lambda expression has captured variables, it is called a closure. For example:
int factor = 10;
var multiplier = (int x) => x * factor;
var result = multiplier(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
In this example, the lambda expression references the local variable factor
. The factor
variable is called an outer variable. And the lambda expression is a closure.
It’s important to note that the lambda expression evaluates the captured variables when it is executed, not when the variables were captured. For example:
var multipliers = new List<Func<int, int>>();
for(int i = 1; i <= 3; i++)
{
multipliers.Add((int x) => x*i);
}
foreach (var multipler in multipliers)
{
int result = multipler(10);
Console.WriteLine(result);
}
Code language: C# (cs)
How it works.
First, define a list of lambda expressions that accept an integer and return an integer:
var multipliers = new List<Func<int, int>>();
Code language: C# (cs)
Second, add three multipliers to the list. Each multiplier will multiply its argument by 1, 2, and 3.
for(int i = 1; i <= 3; i++)
{
multipliers.Add((int x) => x*i);
}
Code language: C# (cs)
Third, iterate over the lambda expression list and execute each of them:
foreach (var multipler in multipliers)
{
int result = multipler(10); // multipler uses 4
Console.WriteLine(result);
}
Code language: C# (cs)
The output is not what you may expect:
40
40
40
Code language: C# (cs)
It returns the same result (40) for the three lambda expressions.
The reason is that after the first for loop, the variable i
is 4. Because the lambda expressions evaluate the capture variables at the time of invocation, not at the defined time. Therefore, all three lambda expressions use the same value of the variable i
.
To fix this, you need to create a local variable inside the for
loop and use that variable as the captured variable for the lambda expressions, like this:
var multipliers = new List<Func<int, int>>();
for(int i = 1; i <= 3; i++)
{
int factor = i;
multipliers.Add((int x) => x*factor);
}
foreach (var multipler in multipliers)
{
int result = multipler(10);
Console.WriteLine(result);
}
Code language: C# (cs)
Output:
10
20
30
Code language: C# (cs)
In this example, each iteration creates a new factor
variable. Therefore, each lambda expression captures a different variable.
Static lambda expressions
When a lambda expression captures variables, the C# compiler needs to create a private class and instantiate it to store a reference to the captured variables. This incurs a small performance.
Starting with C# 9, you can use a static keyword to ensure that the lambda expression doesn’t capture any variables. For example:
var square = static (int x) => x * x;
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
When you use the static
keyword and capture variables, the C# compiler will issue an error. For example:
int factor = 2;
var square = static (int x) => x * factor; // ERROR
var result = square(10);
Console.WriteLine(result); // 100
Code language: C# (cs)
Summary
- A lambda expression defines an anonymous function.
- A lambda expression can capture variables.
- When a lambda expression contains captured variables, it’s called a closure.
- A lambda expression evaluates the captured variables at the time of invocation.