What Lambda Expressions Are
A lambda expression is a concise, inline way to define an anonymous function using the => (goes-to) operator. In LINQ, lambdas are the primary way to supply the predicates, selectors, and comparers that operators like Where, Select, OrderBy, and Aggregate need. The syntax x => x.Price > 100 defines a function taking a parameter x and returning a boolean, and the compiler infers the parameter type from context, whether that's a Func<T, bool> delegate or an Expression<Func<T, bool>> expression tree.
Cricket analogy: A lambda like p => p.Runs > 50 is like a quick instruction to a scorer: 'flag any batter who's crossed fifty,' a compact rule applied to every player in the lineup, similar to how Virat Kohli's half-centuries get tagged in real time.
Lambdas as Delegates vs Expression Trees
The same lambda syntax compiles into two very different things depending on the target type. When assigned to a Func<T, TResult> or Action<T> delegate, the compiler emits actual IL (a method body) that runs directly — this is what LINQ to Objects uses over IEnumerable<T>. When assigned to an Expression<Func<T, TResult>>, the compiler instead builds a data structure describing the lambda's logic as a tree of nodes, which is what LINQ to Entities uses over IQueryable<T> so the ORM can translate it into SQL rather than execute it as .NET code.
Cricket analogy: This is like the difference between a bowler physically running in and delivering the ball (a delegate that executes) versus a coach diagramming the exact seam position and line on a whiteboard for the analyst to later translate into a training drill (an expression tree describing intent).
// Delegate lambda: compiled to executable IL, runs over IEnumerable<T>
Func<Product, bool> isExpensive = p => p.Price > 100;
var expensiveInMemory = products.Where(isExpensive).ToList();
// Expression tree lambda: compiled to a data structure, used with IQueryable<T>
Expression<Func<Product, bool>> isExpensiveExpr = p => p.Price > 100;
var expensiveInDb = dbContext.Products.Where(isExpensiveExpr).ToList();
// Multi-statement lambda with a block body
Func<int, int, int> add = (a, b) =>
{
var sum = a + b;
return sum;
};Capturing Variables (Closures)
Lambdas can capture variables from their enclosing scope, forming a closure. This is extremely common in LINQ, for example capturing a threshold variable inside a Where predicate: products.Where(p => p.Price > threshold). The captured variable is not copied by value; the lambda holds a reference to it, so if the variable changes after the lambda is created but before it executes (particularly relevant with deferred execution or loop variables), the lambda sees the updated value at call time.
Cricket analogy: This is like a fielding coach who sets a rule referencing 'today's par score,' a variable defined outside the drill; if the par score is revised at lunch, every fielder applying that rule afterward uses the new number, not the one from the morning briefing.
Capturing a loop variable in a lambda inside a foreach can lead to subtle bugs in older C# versions or when the captured variable is a for-loop counter declared outside the loop. Since C# 5, foreach loop variables are scoped per-iteration, but a shared for(int i...) counter captured by multiple lambdas will reflect only its final value when those lambdas eventually execute.
- Lambda expressions use the => operator to define concise anonymous functions inline.
- The same lambda syntax compiles to either a delegate (Func/Action) or an Expression<T> depending on target type.
- Delegate lambdas execute directly as IL; expression tree lambdas are data structures interpreted by a provider.
- LINQ to Objects (IEnumerable<T>) uses delegate lambdas; LINQ to Entities (IQueryable<T>) uses expression trees.
- Lambdas can capture outer variables as closures, referencing them rather than copying their value.
- Captured loop variables can cause subtle bugs if their value changes before the lambda executes.
- Lambdas are the primary way to supply predicates and selectors to LINQ operators like Where, Select, and OrderBy.
Practice what you learned
1. What operator is used to define a lambda expression in C#?
2. When a lambda is assigned to an Expression<Func<T,bool>>, what does the compiler generate?
3. Which LINQ variant uses expression trees so queries can be translated into SQL?
4. What does it mean for a lambda to 'capture' a variable?
5. Which LINQ operator commonly takes a lambda predicate to filter a sequence?
Was this page helpful?
You May Also Like
Expression Trees Explained
Learn what expression trees are, how the compiler builds them from lambdas, and how providers like EF Core walk them to generate SQL.
LINQ to SQL and LINQ to Entities
Learn how LINQ to SQL and LINQ to Entities translate C# query expressions into database SQL, and how their architectures differ.
Custom LINQ Extension Methods
Learn how to write your own LINQ-style extension methods on IEnumerable<T>, including deferred execution with yield return and chaining conventions.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics