iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Lambdas

A lambda in C# is an inline anonymous function: parameters => expression-or-block. The compiler infers the delegate or expression type from context, and captured variables are stored on a hidden closure object. Lambdas power LINQ, event handlers, async callbacks, and minimal-API endpoints in modern C#.

Lambdas, closures, expression trees, minimal APIs

EXAMPLE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

// 1) Inline lambdas with LINQ
var nums = new[] { 1, 2, 3, 4, 5, 6 };
var evens = nums.Where(n => n % 2 == 0).Select(n => n * n);
Console.WriteLine(string.Join(",", evens));  // 4,16,36

// 2) Multi-statement lambda with explicit return
Func<string, string> normalise = s => {
    if (string.IsNullOrWhiteSpace(s)) return "";
    return s.Trim().ToLowerInvariant();
};
Console.WriteLine(normalise("  Hello WORLD  "));  // hello world

// 3) Closures — captured variables persist with the lambda
Func<int, int> Counter() {
    var n = 0;
    return _ => ++n;     // each call sees and mutates the same n
}
var bump = Counter();
Console.WriteLine($"{bump(0)} {bump(0)} {bump(0)}");   // 1 2 3

// 4) Local function vs lambda — local functions are usually faster
//    and allow recursion without a workaround
int Fib(int n) => n < 2 ? n : Fib(n - 1) + Fib(n - 2);
Console.WriteLine(Fib(10));   // 55

// 5) Async lambdas
Func<int, Task<int>> Doubled = async x => {
    await Task.Delay(10);
    return x * 2;
};
Console.WriteLine(await Doubled(21));   // 42

// 6) Expression trees — the lambda is data, not code
//    LINQ providers (EF Core) translate these to SQL.
Expression<Func<int, bool>> isAdult = age => age >= 18;
Console.WriteLine(isAdult);                         // age => (age >= 18)
Console.WriteLine(isAdult.Compile().Invoke(21));    // True

// 7) ASP.NET minimal APIs — endpoints ARE lambdas
// var app = WebApplication.CreateBuilder(args).Build();
// app.MapGet("/health", () => Results.Ok(new { ok = true }));
// app.MapPost("/orders", async (Order o, AppDb db) => {
//     db.Orders.Add(o); await db.SaveChangesAsync();
//     return Results.Created(\$"/orders/\{o.Id\}", o);
// });
// app.Run();

Why it matters

A lambda that captures a loop variable used to bite — pre-C# 5 every closure shared the same iteration variable. That was fixed long ago, but if you target older runtimes or use ref locals, copy the value into a local before the lambda to be safe.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
Func<int, int, int> add = (a, b) => a + b;
Action<string> log = msg => Console.WriteLine(msg);
log(add(2, 3).ToString());
Try it Yourself »

Discussion

Loading…