Lambda Expressions
Lambda Expression Overview
A Lambda expression is a concise anonymous function syntax that allows you to define inline functions with less code. It is a core feature of C# functional programming and the foundation of LINQ queries.
Lambda Syntax
The basic syntax of a Lambda expression is: parameters => expression or statement block. => is read as "goes to", mapping the left-side parameters to the right-side operation.
Example
using System;
class Program
{
static void Main()
{
Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
}
}
25
Single-Line and Multi-Line Lambdas
A single-line Lambda directly returns the expression result without the return keyword or curly braces. A multi-line Lambda requires curly braces to wrap the statement block and an explicit return statement.
Example
using System;
class Program
{
static void Main()
{
Func<int, int> singleLine = x => x * x;
Func<int, int> multiLine = x =>
{
int result = x * x;
return result;
};
Console.WriteLine(singleLine(4));
Console.WriteLine(multiLine(4));
}
}
16
16
Type Inference
The compiler can usually infer the types of Lambda parameters from context, eliminating the need for explicit declarations. When the context is ambiguous, you can manually specify the types.
Example
using System;
class Program
{
static void Main()
{
Func<int, int> inferred = x => x + 1;
Func<int, int> explicitType = (int x) => x + 1;
Console.WriteLine(inferred(10));
Console.WriteLine(explicitType(10));
}
}
11
11
Lambdas and Delegates
Lambda expressions can be assigned to delegate types, making them the most concise way to create delegate instances. Compared to traditional anonymous methods or explicit delegate instantiation, Lambdas are shorter.
Example
using System;
delegate int Transform(int x);
class Program
{
static void Main()
{
Transform doubleIt = x => x * 2;
Transform addTen = x => x + 10;
Console.WriteLine(doubleIt(3));
Console.WriteLine(addTen(3));
}
}
6
13
Lambdas with Func and Action
Func<T, TResult> represents a generic delegate with a return value, and Action<T> represents a generic delegate without a return value. Using Lambdas with them is very common.
Example
using System;
class Program
{
static void Main()
{
Func<int, int, int> add = (a, b) => a + b;
Action<string> greet = msg => Console.WriteLine(msg);
Console.WriteLine(add(3, 7));
greet("Hello");
}
}
10
Hello
Lambdas and Predicate
Predicate<T> is a delegate that returns bool, commonly used for filtering and conditional checks. Lambda expressions make defining conditions extremely concise.
Example
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
Predicate<int> isEven = x => x % 2 == 0;
var evens = numbers.FindAll(isEven);
Console.WriteLine(string.Join(", ", evens));
}
}
2, 4, 6
Closures
Lambda expressions can capture outer variables, which is called a closure. The lifetime of captured variables extends with the Lambda — even after the original scope has ended, the variables remain alive.
Example
using System;
class Program
{
static void Main()
{
int factor = 3;
Func<int, int> multiply = x => x * factor;
Console.WriteLine(multiply(5));
factor = 10;
Console.WriteLine(multiply(5));
}
}
15
50
Example
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
foreach (var action in actions)
{
action();
}
}
}
0
1
2
i without creating a copy, all Lambdas will share the same i, and the final output will all be 3. Creating a local copy avoids this issue.
Lambda in LINQ — A Primer
Lambda expressions are central to LINQ queries. Many LINQ methods accept Func or Expression parameters, and Lambdas provide a concise way to write inline conditions, projections, and sorting logic.
Example
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var numbers = new List<int> { 3, 7, 1, 9, 4, 6 };
var big = numbers.Where(x => x > 5);
var doubled = numbers.Select(x => x * 2);
var sorted = numbers.OrderBy(x => x);
Console.WriteLine(string.Join(", ", big));
Console.WriteLine(string.Join(", ", doubled));
Console.WriteLine(string.Join(", ", sorted));
}
}
7, 9, 6
6, 14, 2, 18, 8, 12
1, 3, 4, 6, 7, 9
Expression Trees Introduction
When a Lambda is assigned to Expression<TDelegate>, the compiler generates a data structure (expression tree) rather than executable code. Expression trees can be parsed, modified, and transformed into other forms, such as SQL queries. This is the underlying mechanism for technologies like LINQ to SQL.
Example
using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Expression<Func<int, int>> expr = x => x * x + 1;
Console.WriteLine(expr.Body);
Console.WriteLine(expr.Parameters[0]);
var compiled = expr.Compile();
Console.WriteLine(compiled(4));
}
}
(x * x) + 1
x
17
ℹ️
Expression<Func<int,int>>andFunc<int,int>are different types — the former is a data structure, the latter is an executable delegate.
❓ FAQ
📖 Summary
- Lambda syntax is
parameters => expression, concisely defining anonymous functions - Single-line Lambdas omit curly braces and return; multi-line Lambdas require both
- The compiler can infer Lambda parameter types; explicit declaration is available when needed
- Lambdas can be directly assigned to custom delegates, Func, Action, and Predicate
- Closures allow Lambdas to capture outer variables, extending their lifetime
- When capturing loop variables, create copies to avoid unintended sharing
- Lambdas are the core parameter form for LINQ methods
- Expression trees represent Lambdas as data structures, enabling runtime analysis and transformation
📝 Exercises
- Write a
Func<double, double, double>Lambda that calculates the maximum of two numbers - Use an
Action<string>Lambda to output a log message with a timestamp - Write a closure example: create a counter function that returns an incrementing integer each time it is called
- Use
Wherewith a Lambda to filter strings longer than 5 characters from a list of strings - Assign a
Func<int, bool>Lambda to bothFunc<int, bool>andExpression<Func<int, bool>>, and output theirGetType()results respectively



