<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. C#
  3. Functional C# and LINQ
All lessons in this course

Lesson 38 of 60 12 minIntermediate

Lambda expressions

Write small methods inline with =>, understand type inference and closures, and use lambdas with List, sorting and LINQ.

In the delegates lesson you passed methods like Math.Sqrt to other methods. Writing a whole named method just to say “length greater than 6” is clumsy. A lambda expression is an unnamed method written right where it is needed.

Interactive

From method to lambda

Lambda.cs
static bool IsLong(Beam b){    return b.Length > 6;} var longOnes = beams.Where(IsLong);
A normal named method, passed to Where.
Closures: a lambda can use variables from outside
Func<Beam, bool> isLong = b => b.Length > minLength; // captures minLength, not a copy
B16 m
B24.5 m
B37.2 m
B48 m
B53 m
B65.5 m
B76.5 m
B89 m

beams.Count(isLong) = 4. Moving the slider changes minLength, and the same lambda sees the new value the next time it runs.

Lambda syntax

FormExample
no parameters() => DateTime.Now
one parameterx => x * x
several parameters(a, b) => a + b
explicit types(int a, int b) => a + b
statement bodyb => { var kg = b.Length * 42.2; return kg > 300; }

Read => as “goes to”. The left side lists parameters, the right side is the body. A lambda has no type of its own: it becomes whatever delegate type the place it is used expects (Func<…>, Action<…>, Predicate<…>).

Lambdas everywhere

Everyday.cs
var beams = new List<Beam>{    new("B1", 6.0), new("B2", 4.5), new("B3", 7.2), new("B4", 8.0)}; Beam? b3 = beams.Find(b => b.Mark == "B3");bool anyShort = beams.Exists(b => b.Length < 5);int removed = beams.RemoveAll(b => b.Length > 7.5);beams.Sort((x, y) => y.Length.CompareTo(x.Length));      // longest first Console.WriteLine(b3);Console.WriteLine(anyShort);Console.WriteLine(removed);beams.ForEach(b => Console.Write(b.Mark + " ")); record Beam(string Mark, double Length);
Output
Beam { Mark = B3, Length = 7.2 }
True
1
B3 B1 B2

Closures: capturing variables

A lambda can use local variables from the method around it. It doesn’t copy them: it captures the variable itself, so it sees later changes.

Closure.cs
int clicks = 0;Action onClick = () => clicks++;     // captures 'clicks' onClick();onClick();Console.WriteLine(clicks);           // the lambda changed the real variable Func<int> makeCounter(){    int count = 0;    return () => ++count;            // count lives on inside the lambda}var next = makeCounter();Console.WriteLine($"{next()} {next()} {next()}");
Output
2
1 2 3

static lambdas and discards

Static.cs
Func<double, double> square = static x => x * x;   // 'static': can't capture anything (no hidden allocations)button.Click += (_, _) => Save();                   // _ = parameter you don't use
Quick check

Which lambda matches Func<int, int, int>?

Quick check

After int n = 1; Func<int> f = () => n * 10; n = 5;, what is f()?

Practice

Given List<string> files = new() { "plan.dwg", "model.ifc", "notes.txt", "level2.ifc" };, use lambdas to (1) remove all files that are not .ifc, (2) sort the rest alphabetically, and (3) print them.

Show the solution
Solution.cs
var files = new List<string> { "plan.dwg", "model.ifc", "notes.txt", "level2.ifc" }; files.RemoveAll(f => !f.EndsWith(".ifc", StringComparison.OrdinalIgnoreCase));files.Sort((a, b) => string.Compare(a, b, StringComparison.Ordinal));files.ForEach(f => Console.WriteLine(f));
Output
level2.ifc
model.ifc

Remember

  • A lambda is an inline, unnamed method: (parameters) => body.
  • Its delegate type is inferred from where it is used.
  • Lambdas capture outside variables by reference (closures).
  • Use them with Find, RemoveAll, Sort, events and LINQ.
0 of 60 lessons completed