C# Delegates – Lambda Expressions vs Anonymous Methods
Both lambda expressions and anonymous methods allow us to write methods without explicitly declaring a method name.
They are commonly used with delegates, LINQ, callbacks, and event handling.
1. What is a Lambda Expression in C#?
Definition
A lambda expression is a concise way to define an anonymous function using the lambda operator (=>).
It allows us to write a function directly where it is needed, without creating a separate named method.
Lambda expressions are commonly used with:
-
Func,Action, andPredicatedelegates. -
LINQ queries such as
Where(),Select(), andOrderBy(). -
Event handlers and callbacks.
-
Expression trees.
-
Filtering, sorting, and transforming collections.
Syntax
(parameters) => expression
Or, for multiple statements:
(parameters) =>
{
// Statements
return result;
};
The => operator is called the lambda operator and is commonly read as goes to.
Example 1 – Normal Method vs Lambda Expression
First, consider a normal C# method.
using System;
class Program
{
static int Add(int a, int b)
{
return a + b;
}
static void Main()
{
int result = Add(10, 20);
Console.WriteLine(result);
}
}
Output:
30
Now, write the same logic using a lambda expression.
using System;
class Program
{
static void Main()
{
Func<int, int, int> add = (a, b) => a + b;
int result = add(10, 20);
Console.WriteLine(result);
}
}
Output:
30
Step-by-Step Explanation
Step 1: Declare a Func delegate.
Func<int, int, int> add;
-
First
int– First input parameter. -
Second
int– Second input parameter. -
Third
int– Return type.
Step 2: Assign a lambda expression.
add = (a, b) => a + b;
Here:
-
(a, b)represents the input parameters. -
=>separates the parameters from the function body. -
a + bis the expression that produces the return value.
Step 3: Execute the delegate.
int result = add(10, 20);
The lambda expression calculates 10 + 20 and returns 30.
Execution Flow
Func<int, int, int> add = (a, b) => a + b
|
v
Lambda Expression
|
v
add(10, 20)
|
v
a = 10
b = 20
|
v
a + b
|
v
Returns 30
2. Types of Lambda Expressions
C# supports two primary forms of lambda expressions.
A. Expression Lambda
An expression lambda contains a single expression.
Syntax:
(parameters) => expression
Example:
Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
Output:
25
Explanation:
The lambda accepts an integer and returns its square.
An explicit return statement is not required because the expression produces the result.
B. Statement Lambda
A statement lambda contains a block of statements enclosed in { }.
Syntax:
(parameters) =>
{
// Multiple statements
return result;
};
Example:
Func<int, int, int> calculate = (a, b) =>
{
int sum = a + b;
int result = sum * 2;
return result;
};
Console.WriteLine(calculate(10, 20));
Output:
60
Explanation:
-
a = 10,b = 20. -
Calculate
sum = 30. -
Multiply the sum by 2.
-
Return
60.
Expression Lambda vs Statement Lambda
|
Feature |
Expression Lambda |
Statement Lambda |
|---|---|---|
|
Syntax |
|
|
|
Body |
Single expression |
Statement block |
|
Explicit |
Not needed |
Required when returning a value on that path |
|
Multiple statements |
No |
Yes |
|
Expression tree conversion |
Supported for compatible expressions |
Not supported directly |
|
Best use |
Simple calculations and conditions |
More complex logic |
3. Lambda Expressions with Func, Action, and Predicate
Lambda expressions are commonly assigned to built-in delegates.
Complete Example Program
using System;
class Program
{
static void Main()
{
// Func - Returns a value
Func<int, int, int> add = (a, b) => a + b;
// Action - Returns void
Action<string> display = message =>
{
Console.WriteLine(message);
};
// Predicate - Returns bool
Predicate<int> isEven = number =>
{
return number % 2 == 0;
};
int result = add(10, 20);
display($"Addition: {result}");
Console.WriteLine($"Is Even: {isEven(result)}");
}
}
Output
Addition: 30
Is Even: True
Explanation
-
Funcexecutes the lambda and returns the sum. -
Actionexecutes the lambda to display a message without returning a value. -
Predicateexecutes the lambda to check whether a number is even.
Important: A lambda expression is not itself a delegate type. It is a function expression that can be converted to a compatible delegate type or, when supported, an expression tree.
4. Real-World Example – Lambda Expressions with LINQ
Lambda expressions are extensively used in LINQ.
Consider a collection of employees.
Example Program
using System;
using System.Collections.Generic;
using System.Linq;
public class Employee
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Salary { get; set; }
}
class Program
{
static void Main()
{
List<Employee> employees = new()
{
new Employee { Id = 1, Name = "John", Salary = 30000 },
new Employee { Id = 2, Name = "David", Salary = 60000 },
new Employee { Id = 3, Name = "Peter", Salary = 45000 },
new Employee { Id = 4, Name = "James", Salary = 70000 }
};
var result = employees
.Where(e => e.Salary > 50000)
.OrderBy(e => e.Name)
.ToList();
foreach (var employee in result)
{
Console.WriteLine(
$"{employee.Name} - {employee.Salary}");
}
}
}
Output
David - 60000
James - 70000
Step-by-Step Explanation
Step 1: Filter employees based on salary.
.Where(e => e.Salary > 50000)
The lambda accepts an employee and checks whether the salary is greater than 50,000.
Step 2: Sort the filtered employees.
.OrderBy(e => e.Name)
The lambda returns each employee's name, which LINQ uses as the sorting key.
Step 3: Convert the result into a list.
.ToList();
Step 4: Display the matching employees.
Execution Flow
Employee Collection
|
v
Where(e => e.Salary > 50000)
|
+-- John : 30000 -> Excluded
|
+-- David : 60000 -> Included
|
+-- Peter : 45000 -> Excluded
|
+-- James : 70000 -> Included
|
v
OrderBy(e => e.Name)
|
v
David
James
|
v
ToList()
|
v
Display Results
Key Points – Lambda Expressions
-
A lambda expression defines an anonymous function using
=>. -
It reduces the need to declare separate named methods for short operations.
-
It can be assigned to compatible delegates such as
Func,Action, andPredicate. -
It supports both expression bodies and statement bodies.
-
It is widely used in LINQ, callbacks, and event handling.
-
Lambda expressions can capture variables from their enclosing scope. This is known as a closure.
-
Compatible expression lambdas can be converted into expression trees using
Expression<TDelegate>. -
In EF Core, expression trees allow LINQ expressions to be inspected and translated into SQL.
5. What is an Anonymous Method in C#?
Definition
An anonymous method is a method without an explicitly declared name, defined using the delegate keyword.
It allows us to define a block of executable code directly and assign it to a compatible delegate.
Anonymous methods were introduced in C# 2.0, while lambda expressions were introduced in C# 3.0.
Syntax
delegate (parameters)
{
// Statements
};
Example Program
using System;
class Program
{
static void Main()
{
Func<int, int, int> add = delegate(int a, int b)
{
return a + b;
};
int result = add(10, 20);
Console.WriteLine(result);
}
}
Output
30
Step-by-Step Explanation
Step 1: Declare a delegate variable.
Func<int, int, int> add;
Step 2: Assign an anonymous method.
add = delegate(int a, int b)
{
return a + b;
};
The delegate keyword defines the anonymous method.
Step 3: Invoke the delegate.
int result = add(10, 20);
The anonymous method executes and returns 30.
Execution Flow
Func<int, int, int> add
|
v
delegate(int a, int b)
{
return a + b;
}
|
v
add(10, 20)
|
v
a = 10
b = 20
|
v
Returns 30
6. Anonymous Method vs Lambda Expression – Same Example
Let's implement the same addition operation in three different ways.
A. Named Method
static int Add(int a, int b)
{
return a + b;
}
Func<int, int, int> calculate = Add;
B. Anonymous Method
Func<int, int, int> calculate = delegate(int a, int b)
{
return a + b;
};
C. Lambda Expression
Func<int, int, int> calculate = (a, b) => a + b;
All three can be invoked using:
Console.WriteLine(calculate(10, 20));
Output:
30
Comparison Diagram
C# Function Definitions
|
+--------------+--------------+
| | |
v v v
Named Method Anonymous Method Lambda
| | |
v v v
Add(a, b) delegate(a,b) (a,b) =>
| | |
+--------------+--------------+
|
v
Execute Addition
|
v
Return 30
7. Difference Between Anonymous Methods and Lambda Expressions
|
Feature |
Anonymous Method |
Lambda Expression |
|---|---|---|
|
Introduced |
C# 2.0 |
C# 3.0 |
|
Keyword/operator |
|
|
|
Syntax |
More verbose |
More concise |
|
Method name |
Not required |
Not required |
|
Parameters |
Explicit types or omitted parameter list |
Explicit or inferred types |
|
Expression body |
No |
Yes |
|
Statement body |
Yes |
Yes |
|
Delegate support |
Yes |
Yes |
|
Expression tree support |
No direct conversion |
Yes, for compatible expression lambdas |
|
LINQ usage |
Possible with delegate-based APIs |
Preferred and widely used |
|
Closures |
Supported |
Supported |
|
Modern C# preference |
Less common |
Generally preferred |
Important Difference – Expression Trees
One major technical difference is that compatible lambda expressions can be converted into expression trees, whereas anonymous methods cannot.
Lambda expression:
using System;
using System.Linq.Expressions;
Expression<Func<int, bool>> isAdult = age => age >= 18;
This is valid.
Anonymous method:
Expression<Func<int, bool>> isAdult =
delegate(int age)
{
return age >= 18;
};
This produces a compilation error because an anonymous method cannot be converted to an expression tree.
Why Is This Important in EF Core?
Consider:
var employees = dbContext.Employees
.Where(e => e.Salary > 50000)
.ToList();
Here, dbContext.Employees is normally an IQueryable<Employee>.
The Where() call uses an expression tree representing:
e => e.Salary > 50000
EF Core can analyze this expression and translate it into SQL.
Conceptually:
SELECT *
FROM Employees
WHERE Salary > 50000;
The expression tree is important because EF Core needs to understand the structure of the condition, not merely execute a compiled delegate in memory.
8. Important Concept – Closures in Lambda Expressions and Anonymous Methods
Both lambda expressions and anonymous methods can access variables declared in their enclosing scope.
This is called a closure.
Example Program
using System;
class Program
{
static void Main()
{
int bonus = 5000;
Func<int, int> calculateSalary =
salary => salary + bonus;
Console.WriteLine(calculateSalary(30000));
bonus = 10000;
Console.WriteLine(calculateSalary(30000));
}
}
Output
35000
40000
Explanation
The lambda expression captures the local variable bonus.
When bonus changes from 5000 to 10000, the lambda observes the updated value.
It does not automatically preserve a snapshot of the original value.
Execution Flow
bonus = 5000
|
v
Create Lambda
|
v
calculateSalary(30000)
|
v
30000 + 5000 = 35000
|
v
bonus = 10000
|
v
calculateSalary(30000)
|
v
30000 + 10000 = 40000
The equivalent anonymous method is:
int bonus = 5000;
Func<int, int> calculateSalary = delegate(int salary)
{
return salary + bonus;
};
This also captures bonus.
Important: Captured variables may have their lifetimes extended by the compiler-generated closure. In long-lived callbacks or event handlers, this can affect memory usage and object lifetime.
9. Important Interview Questions
Q1. Are lambda expressions and anonymous methods the same?
They are related but not identical.
Both define anonymous functions and can be assigned to compatible delegates. However, lambda expressions provide more concise syntax and support expression tree conversion for compatible expression-bodied lambdas.
Q2. Can lambda expressions contain multiple statements?
Yes.
Func<int, int> calculate = x =>
{
int result = x * 2;
return result + 10;
};
Q3. Can anonymous methods return values?
Yes, provided their delegate signature supports a return value.
Func<int, int> square = delegate(int x)
{
return x * x;
};
Q4. Can lambda expressions access local variables?
Yes. Lambda expressions can capture local variables from their enclosing scope.
This mechanism is called a closure.
Q5. Can anonymous methods be used with LINQ?
Yes, when the LINQ API expects a compatible delegate.
For example:
List<int> numbers = new() { 10, 15, 20, 25 };
var result = numbers
.Where(delegate(int x) { return x > 15; })
.ToList();
This works because Enumerable.Where() accepts Func<T, bool>.
However, anonymous methods cannot directly replace expression trees in Queryable.Where().
Q6. Which should we use in modern C# applications?
Lambda expressions are generally preferred because they are concise, readable, and work naturally with LINQ.
Named methods remain useful when logic is complex, reused extensively, or benefits from a descriptive method name.
10. Final Key Points for Interviews
-
Lambda expressions use the
=>operator. -
Anonymous methods use the
delegatekeyword. -
Both allow anonymous functions without explicitly declaring a named method.
-
Both can be assigned to compatible delegates.
-
Lambda expressions support expression and statement bodies.
-
Anonymous methods use statement blocks.
-
Both can capture variables from their enclosing scope.
-
Compatible expression lambdas support expression tree conversion.
-
Anonymous methods cannot be directly converted into expression trees.
-
Lambda expressions are generally preferred in modern C#, particularly with LINQ and EF Core.
11. Interview-Ready Answers
Q1. What is a lambda expression?
A lambda expression is a concise way to define an anonymous function using the => operator. It can accept parameters, execute logic, and return a value. Lambda expressions are commonly used with Func, Action, Predicate, LINQ, and expression trees.
Q2. What is the difference between anonymous methods and lambda expressions?
Anonymous methods use the delegate keyword, whereas lambda expressions use the => operator. Both allow us to write anonymous functions, but lambda expressions provide shorter syntax and can be converted into expression trees when their form is supported. This makes lambda expressions particularly useful in LINQ and Entity Framework Core.
Easy way to remember:
Anonymous Method:
delegate(int x) { return x * 2; }
Lambda Expression:
x => x * 2
Both:
Define anonymous functions
Major Difference:
Lambda expressions support expression trees
Anonymous methods do not