In this article, we’re going to learn what Lambda Expressions in C# are in detail.
Let’s begin.
What Are Lambda Expressions?
Lambda expressions were first introduced in C# 3 in 2007. Since then, Lambda expressions have helped us simplify and minimize the verbosity of our codebase, undoubtedly.
Lambda expressions are simply anonymous/delegate functions, but with a simple and expressive syntax.
We can assign the lambda expression to a variable, pass it as a parameter or specify it as a property.
Usage of Lambda Expressions
Let’s see some of the most common usages of lambda expressions.
Language Integrated Query (LINQ)
LINQ heavily uses lambda expressions:
var fruits = new[] { "apple", "orange", "mango", "pineapple" }; var fruitsOrdered = fruits.OrderBy(name => name).ToArray(); var fruitsUpperCase = Fruits.Select(name => name.ToUpper()).ToArray(); var mango = Fruits.First(name => name == "mango");
Here, name => name
, name => name.ToUpper()
, name => name == mango
are the lambda expressions (in form of delegates) passed to OrderBy
, Select
, First
methods respectively.
Minimal API
In ASP.NET Core 6, Minimal APIs are introduced.
A simple GET API that returns “Hello World!”:
var app = WebApplication.Create(args); app.MapGet("/", () => "Hello World!"); app.Run();
Here, () => "Hello World!"
is the lambda expression passed as the second parameter to MapGet
method.
Events
Lambda expressions can be used to subscribe to events as long as they share the same method signature of the event’s delegate type. In our case, EventHandler
is a built-in delegate type. Now, we know events, delegates, and lambda expressions are closely related to each other:
public event EventHandler Event;
Lambda expression subscribing to the event:
Event += (obj, eventArgs) => { Console.WriteLine("Event raised!"); };
Syntax of Lambda Expressions
The syntax of lambda expressions contains parameters on the left side, and expressions or statements on the right side (body), separated by the =>
operator.
Expression Lambda
Expression lambda contains the single expression in the lambda body:
(<parameters>) => expression
A sample for expression lambda with return value:
var sum = () => 1 + 1;
Another one, without any return value:
var sayHello = () => Console.WriteLine("Hello");
Another sample, accepting parameters and no return value:
var sayName = (string name) => Console.WriteLine($"Hello {name}"); //or Action<string> sayName = name => Console.WriteLine($"Hello {name}"); var sayFullName = (string firstName, string lastName) => Console.WriteLine($"Hello {firstName} {lastName}");
Note: The parentheses ()
are not required for a single parameter. But, it applies only to explicitly declared target types. However, it is mandatory when there is more than one parameter.
Statement Lambda
Statement lambdas enclose one or more statements in the lambda body with curly braces {}
:
(<parameters>) => { <statements> }
Sample of statement lambda with parameters and return type:
var sum = (int a, int b) => { var sum = a + b; return sum; }
Executing Lambda Expressions:
Lambda expressions assigned to variables, parameters, or properties will hold only the reference to the lambda expressions. Hence, we don’t execute lambdas at the time of assigning. Whenever needed, we can execute like methods:
sum(); sayHello(); sayName("Code Maze"); sayFullName("Code", "Maze"); sum(1, 1);
Async/Await With Lambda Expressions
Likewise the regular methods, we can use async
, await
keywords in the lambda expressions to take advantage of asynchronous operations.
For instance, let us look at a simple async expression lambda which will wait for 1000 milliseconds:
var lambda = async () => await Task.Delay(1000); await lambda();
Similarly, for statement lambda:
var lambda = async () => { await Task.Delay(1000); Console.WriteLine("Completed async task"); }; await lambda();
Lambda Expression Type
In general, Lambda expressions do not have any type. However, we can assign them to the Action
or Func
delegate type based on the parameter and return type.
Before C# 10, we need to specify the type explicitly while assigning variables:
Action sayHello = () => Console.WriteLine("Hello!"); Action<string> sayName = (name) => Console.WriteLine($"Hello {name}"); Func<int> sum = () => 1 + 1; Func<int, int> square = (number) => number * 2;
From C# 10 onward, the compiler will naturally infer the type of variable as Action
or Func
delegate:
var sayHello = () => Console.WriteLine("Hello!"); var sayName = (string name) => Console.WriteLine($"Hello {name}"); var sum = () => 1 + 1; var square = (int number) => number * 2;
Note: Whenever we use var
keyword to declare the lambda expression, we need to specify the parameter type explicitly.
In this example, If we infer the type of sayHello
variable in Visual Studio, it will show Action?
. Similarly for other variables sayName
, sum
, square
, the type is inferred as Action<string>
, Func<int>
, Func<int, int>
.
To learn more about Func and Action delegate types, please refer to the C# delegates article.
Return Type of Lambda Expression
Generally, the compiler infers the return type from the lambda expression body’s expression or statements. But, in rare cases, we may need to specify the return type explicitly:
Func<int, object?> returnNullOrNumber = object? (number) => { return number > 0 ? number : null; };
In the above example, the return type is object?
. Because we return two different values int
and null
.
Conclusion
In this article, we have learned about Lambda expressions and their usage through various examples.