Skip to content
Theory · Lambdas and LINQ · lesson 2 of 10

Lambda expressions

In the previous lesson, every method we passed was first declared on its own and given a name: Twice, Square, IsEven. For a one-line calculation needed in one place of the program, that is extra work.

The same goes for a recipe card. To hand a friend a short recipe, you do not have to enter it into a cookbook under a title first. You can write it right on the card, at the moment you hand it over.

In C# such a card is written right where a delegate is needed:

C#
Func<int, int> twice = x => x * 2;
Console.WriteLine(twice(5)); // 10

List<int> nums = [4, -1, 6, -3];
nums.RemoveAll(n => n < 0);
Console.WriteLine(string.Join(" ", nums)); // 4 6

Let's go through the program line by line:

  1. x => x * 2 is a method without a name: it takes x and returns x * 2. It goes straight into the variable twice.
  2. twice(5) calls it like any delegate and prints 10.
  3. nums.RemoveAll(n => n < 0) gets the check right in the argument. The list method calls it for each item and removes those for which it returned true.
  4. The list keeps 4 and 6.

How a lambda is built

The notation x => x * 2 is called a lambda expression, or a lambda: a method without a name, written right where it is needed. It has three parts:

  • x to the left of => is the parameter;
  • => is the same arrow as in short methods such as int Twice(int x) => x * 2;;
  • x * 2 to the right is the body: the lambda returns its value.

The parameter's type is not written in the lambda. The compiler takes it from the delegate the lambda goes into. Func<int, int> takes an int, so x is an int too. And RemoveAll on a List<int> expects a Predicate<int>, so n is also an int.

Interviewers like to ask this: what is a lambda expression? The answer: a method without a name, written right inside an expression and assigned to a delegate or passed to a method.

Forms of a lambda

A lambda can do what a method does: take several parameters or none, run several statements. Each case has its own form:

C#
Func<int, int, int> add = (a, b) => a + b;
Func<int> answer = () => 42;
Func<int, int> next = x =>
{
    int y = x + 1;
    return y * 10;
};
Action<string> greet = name => Console.WriteLine($"Hi, {name}!");
Console.WriteLine(add(2, 3)); // 5
Console.WriteLine(answer());  // 42
Console.WriteLine(next(4));   // 50
greet("Ann");                 // Hi, Ann!

One parameter

A single parameter needs no parentheses: x => x * 2. This is the most common form.

Several parameters or none

Parameters are listed in parentheses, separated by commas: (a, b) => a + b. A lambda with no parameters starts with empty parentheses: () => 42.

A body of several statements

When one line is not enough, the body goes in braces, as in a method. Then return gives back the value: the lambda next first computes y and then returns y * 10. A lambda for an Action returns nothing, so it needs no return.

Explicit parameter types

You can write the parameter's type yourself: (int x) => x * 2. Then the parentheses are needed even around a single parameter. More often the type is left out, and the delegate supplies it.

A card without a cookbook

Here the recipe card analogy ends. A recipe on a card makes sense on its own, but a lambda needs a delegate. Without one, the compiler knows neither the parameter type nor the return type: x => x * 2 fits an int as well as a double.

Common mistake

The lambda was put into a variable declared with var:

C#
var twice = x => x * 2; // ✗
Console.WriteLine(twice(5));
TEXT
error CS8917: The delegate type could not be inferred.

The program does not compile. There is not a single type to the right of =, and the compiler has no way to learn what x is. There are two fixes:

  1. Name the delegate: Func<int, int> twice = x => x * 2;.
  2. Give the parameter a type: var twice = (int x) => x * 2;. Then the compiler picks the type Func<int, int> for the variable itself.

Key points

  • A lambda is a method without a name, written right where it is needed: x => x * 2.
  • Parameters go to the left of =>, the body to the right; several parameters or none go in parentheses, several statements in braces with return.
  • A lambda gets its parameter and return types from the delegate, so var twice = x => x * 2; does not compile.