Lambda Expressions

A lambda expression is an unnamed method written in place of a delegate instance. The compiler immediately converts the lambda expression to either:

Given the following delegate type:

delegate int Transformer (int i);

we could assign and invoke the lambda expression x => x * x as follows:

Transformer sqr = x => x * x;
Console.WriteLine (sqr(3));    // 9

Note

Internally, the compiler resolves lambda expressions of this type by writing a private method, and moving the expression’s code into that method.

A lambda expression has the following form:

(parameters) => expression-or-statement-block

For convenience, you can omit the parentheses if and only if there is exactly one parameter of an inferable type.

In our example, there is a single parameter, x, and the expression is x * x:

x => x * x;

Each parameter of the lambda expression corresponds to a delegate parameter, and the type of the expression (which may be void) corresponds to the return type of the delegate.

In our example, x corresponds to parameter i, and the expression x * x corresponds to the return type int, therefore being compatible with the Transformer delegate.

A lambda expression’s code can be a statement block instead of an expression. We can rewrite our example as follows:

x => { return x * x; };

Lambda expressions are used most commonly with the Func and Action delegates, so you will most often see our earlier expression written as follows:

Func<int,int> sqr = x => x * x;

The compiler can usually infer the type of lambda parameters contextually. When this is not the case, you can specify parameter types explicitly:

Func<int,int> sqr = (int x) => x * x;

Here’s an example of an expression that accepts two parameters:

Func<string,string,int> totalLength =
 (s1, s2) => s1.Length + s2.Length;

int total = totalLength ("hello", "world");  // total=10;

Assuming Clicked is an event of type EventHandler, the following attaches an event handler via a lambda expression:

obj.Clicked += (sender,args) => Console.Write ("Click");

A lambda expression can reference the local variables and parameters of the method in which it’s defined (outer variables). For example:

static void Main()
{
  int factor = 2;
  Func<int, int> multiplier = n => n * factor;
  Console.WriteLine (multiplier (3));           // 6
}

Outer variables referenced by a lambda expression are called captured variables. A lambda expression that captures variables is called a closure. Captured variables are evaluated when the delegate is actually invoked, not when the variables were captured:

int factor = 2;
Func<int, int> multiplier = n => n * factor;
factor = 10;
Console.WriteLine (multiplier (3));           // 30

Lambda expressions can themselves update captured variables:

int seed = 0;
Func<int> natural = () => seed++;
Console.WriteLine (natural());           // 0
Console.WriteLine (natural());           // 1
Console.WriteLine (seed);                // 2

Captured variables have their lifetimes extended to that of the delegate. In the following example, the local variable seed would ordinarily disappear from scope when Natural finished executing. But because seed has been captured, its lifetime is extended to that of the capturing delegate, natural:

static Func<int> Natural()
{
  int seed = 0;
  return () => seed++;      // Returns a closure
}
static void Main()
{
  Func<int> natural = Natural();
  Console.WriteLine (natural());      // 0
  Console.WriteLine (natural());      // 1
}