C# Programming Tutorial 0/45 lessons ~6 min read Lesson 35

    Lambda Expressions

    Lambdas are inline anonymous functions — (x, y) => x + y — powering LINQ, Task.Run, and fluent configuration.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Lambdas are inline anonymous functions — (x, y) => x + y — powering LINQ, Task.Run, and fluent configuration. Expression lambdas compile to delegates; expression trees (Expression<Func>) enable EF Core SQL translation.

    Closures capture outer variables by reference — interviewers ask closure loop bug in foreach before C# 5 and allocation implications.

    The story

    A product catalog API filters premium items — price at or above $1,000 — within a specific category for a "Luxury" storefront page. A static lambda defines the premium predicate once without capturing local variables, avoiding extra heap allocations on every request in a high-traffic e-commerce service.

    Understanding the topic

    Key concepts

    • Syntax: (params) => expression or { statements }
    • Implicit typing on parameters when delegate known.
    • Closure captures local variables lifetime extended.
    • Expression> vs Func — tree vs delegate.
    • Static lambda (C# 9) avoids capture allocation.
    • Discard _ for unused parameters.

    Step-by-step explanation

    1. Compiler generates closure class for captures.
    2. Assign lambda to Action/Func matching signature.
    3. Pass to LINQ Where, Select methods.
    4. Expression trees analyzed by EF provider.
    5. Local functions alternative when reuse in method.
    6. ref readonly params in advanced scenarios.

    Practical code example

    LINQ filtering with lambda and static lambda avoiding capture:

    csharp
    namespace TechLearningPro.Lambdas;
    public record Product(string Category, decimal Price);
    public static class ProductFilters
    {
    private static readonly Func<Product, bool> IsPremium =
    static p => p.Price >= 1000m; // static lambda — no closure
    public static IEnumerable<Product> ExpensiveInCategory(
    IEnumerable<Product> products,
    string category) =>
    products.Where(p => p.Category == category && IsPremium(p));
    }

    Line-by-line code explanation

    • record Product(string Category, decimal Price) is the entity being filtered.
    • Func<Product, bool> IsPremium = static p => p.Price >= 1000m stores a reusable predicate delegate.
    • static p => marks a static lambda that cannot capture surrounding locals — zero closure allocation.
    • p.Price >= 1000m defines the premium threshold inline.
    • ExpensiveInCategory(..., string category) combines category and premium filters.
    • products.Where(p => p.Category == category && IsPremium(p)) chains LINQ with the named predicate.
    • p.Category == category captures the method parameter in the lambda — allowed here because it is a parameter, not a local.
    • IsPremium(p) reuses the static predicate instead of duplicating the price check.

    Key takeaway: static lambda cannot capture locals — zero allocation closure. Combine with local function for complex multi-line filters.

    Real-world use

    Where you'll use this in production

    • LINQ queries in repositories.
    • FluentValidation rule definitions.
    • Task continuations ContinueWith (prefer await).
    • ASP.NET route filters inline predicates.

    Best practices

    • Use static lambda when no capture needed.
    • Extract complex lambdas to named local functions.
    • Avoid modifying captured variables confusingly.
    • Expression trees only when provider needs them.
    • Keep lambdas short for readability.

    Common mistakes

    • Closure loop variable bug (historical — foreach fixed).
    • Accidental capture of large object graph.
    • Statement lambda where expression sufficient.
    • Using Func where Expression needed for EF.

    Advanced interview questions

    Q1BeginnerLambda syntax?
    (args) => expression or block body with return.
    Q2BeginnerClosure?
    Lambda captures outer variable; compiler wraps in display class.
    Q3IntermediateExpression vs delegate lambda?
    Expression builds tree for providers; Func compiles to IL.
    Q4Intermediatestatic lambda benefit?
    No closure allocation; cannot access instance/locals.
    Q5AdvancedEF Core filter by dynamic user input safely.
    Build Expression> with ParameterExpression; avoid string eval; parameterized SQL.

    Summary

    Lambdas provide concise inline delegates. Closures capture context — mind allocations. Expression trees enable LINQ-to-SQL translation. static lambda optimizes hot paths. Next: generics for type-safe reusable code.

    Ready to mark this lesson complete?Track your journey across the entire course.