Skip to main content

C# Lambda Expressions

Introduction

Lambda expressions are a concise way to represent anonymous methods in C#. Introduced in C# 3.0, they provide a more elegant syntax for creating delegates or expression tree types. Lambda expressions are particularly useful when you need to pass a small piece of code as an argument to a method, or when working with LINQ queries.

In this tutorial, we'll explore lambda expressions, their syntax, and how they can simplify your code. By the end, you'll be comfortable using lambda expressions in your C# applications.

What Are Lambda Expressions?

A lambda expression is an anonymous function that you can use to create delegates or expression tree types. Instead of declaring a separate method, you can write the method implementation inline. This makes your code more readable and reduces the number of lines needed.

The basic syntax of a lambda expression is:

csharp
(parameters) => expression

or

csharp
(parameters) => { statements; }

The => symbol is called the lambda operator (or "goes to" operator).

Basic Lambda Syntax

Let's start with a simple example to understand the syntax:

csharp
// Traditional delegate
Func<int, int> square = delegate(int x) { return x * x; };

// Equivalent lambda expression
Func<int, int> squareLambda = x => x * x;

Console.WriteLine(square(5)); // Output: 25
Console.WriteLine(squareLambda(5)); // Output: 25

In the lambda expression x => x * x:

  • x is the input parameter
  • => is the lambda operator
  • x * x is the expression that's evaluated and returned

Multiple Parameters

Lambda expressions can have zero, one, or multiple parameters:

csharp
// No parameters
Action sayHello = () => Console.WriteLine("Hello!");

// One parameter (parentheses optional for single parameter)
Func<int, bool> isPositive = x => x > 0;

// Multiple parameters
Func<int, int, int> add = (x, y) => x + y;

sayHello(); // Output: Hello!
Console.WriteLine(isPositive(10)); // Output: True
Console.WriteLine(isPositive(-5)); // Output: False
Console.WriteLine(add(3, 7)); // Output: 10

Multiple Statements

If your lambda expression requires multiple statements, you can use curly braces and include a return statement:

csharp
Func<int, int> factorial = n =>
{
int result = 1;
for (int i = 1; i <= n; i++)
{
result *= i;
}
return result;
};

Console.WriteLine(factorial(5)); // Output: 120

Lambda Expressions with Delegates

Lambda expressions are commonly used with delegates in C#. They provide a concise way to define delegate methods inline.

Working with Predefined Delegates

C# provides several predefined delegate types like Action<>, Func<>, and Predicate<>:

csharp
// Action delegate (no return value)
Action<string> greet = name => Console.WriteLine($"Hello, {name}!");
greet("Alice"); // Output: Hello, Alice!

// Func delegate (returns a value)
Func<double, double, double> power = (x, y) => Math.Pow(x, y);
Console.WriteLine(power(2, 3)); // Output: 8

// Predicate delegate (returns a boolean)
Predicate<int> isEven = num => num % 2 == 0;
Console.WriteLine(isEven(4)); // Output: True
Console.WriteLine(isEven(7)); // Output: False

Custom Delegates with Lambda

You can also use lambda expressions with custom delegate types:

csharp
// Define a custom delegate
delegate string Formatter(string text);

// Use the delegate with a lambda expression
Formatter capitalize = s => s.ToUpper();
string result = capitalize("hello world");
Console.WriteLine(result); // Output: HELLO WORLD

Lambda Expressions with Collections

Lambda expressions really shine when working with collections and LINQ (Language Integrated Query). They make filtering, transforming, and querying data much more readable.

Filtering Collections

csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// Filter even numbers
var evenNumbers = numbers.Where(n => n % 2 == 0);

Console.WriteLine("Even numbers:");
foreach (var num in evenNumbers)
{
Console.WriteLine(num); // Output: 2, 4, 6, 8, 10
}

Transforming Collections

csharp
// Transform each number to its square
var squares = numbers.Select(n => n * n);

Console.WriteLine("Squares:");
foreach (var square in squares)
{
Console.WriteLine(square); // Output: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
}

Sorting Collections

csharp
List<string> fruits = new List<string> { "apple", "banana", "cherry", "date", "fig" };

// Sort by length
var sortedByLength = fruits.OrderBy(f => f.Length);

Console.WriteLine("Fruits sorted by length:");
foreach (var fruit in sortedByLength)
{
Console.WriteLine(fruit); // Output: fig, date, apple, cherry, banana
}

Real-World Applications

Now let's look at some real-world applications of lambda expressions to better understand their practical use.

Event Handlers

Lambda expressions can simplify event handling:

csharp
// Traditional event handler
button.Click += new EventHandler(button_Click);
void button_Click(object sender, EventArgs e)
{
MessageBox.Show("Button clicked!");
}

// Using lambda expression
button.Click += (sender, e) => MessageBox.Show("Button clicked!");

Data Processing

Lambda expressions make data processing operations more readable:

csharp
List<Product> products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 1200, Category = "Electronics" },
new Product { Id = 2, Name = "Desk Chair", Price = 250, Category = "Furniture" },
new Product { Id = 3, Name = "Headphones", Price = 100, Category = "Electronics" },
new Product { Id = 4, Name = "Coffee Table", Price = 150, Category = "Furniture" }
};

// Find expensive electronics
var expensiveElectronics = products
.Where(p => p.Category == "Electronics" && p.Price > 500)
.Select(p => new { p.Name, p.Price });

foreach (var item in expensiveElectronics)
{
Console.WriteLine($"{item.Name}: ${item.Price}"); // Output: Laptop: $1200
}

// Calculate total inventory value
decimal totalValue = products.Sum(p => p.Price);
Console.WriteLine($"Total inventory value: ${totalValue}"); // Output: Total inventory value: $1700

Custom Sorting

Lambda expressions allow for complex sorting logic:

csharp
List<Student> students = new List<Student>
{
new Student { Name = "Alice", GPA = 3.8, GraduationYear = 2023 },
new Student { Name = "Bob", GPA = 3.6, GraduationYear = 2024 },
new Student { Name = "Charlie", GPA = 3.9, GraduationYear = 2023 },
new Student { Name = "Diana", GPA = 3.7, GraduationYear = 2024 }
};

// Sort first by graduation year, then by GPA (descending)
var sortedStudents = students
.OrderBy(s => s.GraduationYear)
.ThenByDescending(s => s.GPA);

Console.WriteLine("Students sorted by graduation year and GPA:");
foreach (var student in sortedStudents)
{
Console.WriteLine($"{student.Name}: Class of {student.GraduationYear}, GPA {student.GPA}");
}
/* Output:
Charlie: Class of 2023, GPA 3.9
Alice: Class of 2023, GPA 3.8
Diana: Class of 2024, GPA 3.7
Bob: Class of 2024, GPA 3.6
*/

Capturing Variables in Lambda Expressions

Lambda expressions can access variables defined in the enclosing scope. This is known as "variable capturing" or "closures":

csharp
int factor = 10;
Func<int, int> multiplier = n => n * factor;

Console.WriteLine(multiplier(5)); // Output: 50

factor = 20;
Console.WriteLine(multiplier(5)); // Output: 100 (the lambda uses the updated value)

Be careful with closures, as they capture the variable itself, not just its value at the time of lambda creation.

Best Practices for Lambda Expressions

  1. Keep them simple: Lambda expressions should be short and focused. If your lambda is becoming complex, consider using a named method instead.

  2. Avoid side effects: Ideally, lambda expressions should not modify external state.

  3. Use meaningful parameter names: Even in short lambdas, descriptive names help readability.

  4. Consider readability: Sometimes a traditional method is more readable than a complex lambda expression.

Summary

Lambda expressions in C# provide a concise and expressive way to create anonymous methods. They're especially useful for:

  • Creating short, inline function definitions
  • Working with delegates and events
  • Writing LINQ queries
  • Processing collections
  • Defining callbacks

By mastering lambda expressions, you can write more readable and maintainable code with less boilerplate.

Additional Resources

Exercises

  1. Create a lambda expression that calculates the average of a list of integers.
  2. Write a lambda expression to filter a list of strings to only include those with more than 5 characters.
  3. Use lambda expressions with LINQ to find the most expensive product in each category from a list of products.
  4. Create a custom sorting function using a lambda expression that sorts a list of people by last name, then by first name.
  5. Implement a simple event handler using a lambda expression.

Try these exercises to strengthen your understanding of lambda expressions in C#!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)