Lambda expressions

Remarks

A lambda expression is a syntax for creating anonymous functions inline. More formally, from the C# Programming Guide:

A lambda expression is an anonymous function that you can use to create delegates or expression tree types. By using lambda expressions, you can write local functions that can be passed as arguments or returned as the value of function calls.

A lambda expression is created by using the => operator. Put any parameters on the lefthand side of the operator. On the righthand side, put an expression that can use those parameters; this expression will resolve as the return value of the function. More rarely, if necessary, a whole {code block} can be used on the righthand side. If the return type is not void, the block will contain a return statement.

Lambda Expression as an Event Handler

Lambda expressions can be used to handle events, which is useful when:

  • The handler is short.
  • The handler never needs to be unsubscribed.

A good situation in which a lambda event handler might be used is given below:

smtpClient.SendCompleted += (sender, args) => Console.WriteLine("Email sent");

If unsubscribing a registered event handler at some future point in the code is necessary, the event handler expression should be saved to a variable, and the registration/unregistration done through that variable:

EventHandler handler = (sender, args) => Console.WriteLine("Email sent");

smtpClient.SendCompleted += handler;
smtpClient.SendCompleted -= handler;

The reason that this is done rather than simply retyping the lambda expression verbatim to unsubscribe it (-=) is that the C# compiler won't necessarily consider the two expressions equal:

EventHandler handlerA = (sender, args) => Console.WriteLine("Email sent");
EventHandler handlerB = (sender, args) => Console.WriteLine("Email sent");
Console.WriteLine(handlerA.Equals(handlerB)); // May return "False"

Note that if additional statements are added to the lambda expression, then the required surrounding curly braces may be accidentally omitted, without causing compile-time error. For example:

smtpClient.SendCompleted += (sender, args) => Console.WriteLine("Email sent"); emailSendButton.Enabled = true;

This will compile, but will result in adding the lambda expression (sender, args) => Console.WriteLine("Email sent"); as an event handler, and executing the statement emailSendButton.Enabled = true; immediately. To fix this, the contents of the lambda must be surrounded in curly braces. This can be avoided by using curly braces from the start, being cautious when adding additional statements to a lambda-event-handler, or surrounding the lambda in round brackets from the start:

smtpClient.SendCompleted += ((sender, args) => Console.WriteLine("Email sent"));
//Adding an extra statement will result in a compile-time error

Lambda Expressions as Shorthand for Delegate Initialization

public delegate int ModifyInt(int input);
ModifyInt multiplyByTwo = x => x * 2;

The above Lambda expression syntax is equivalent to the following verbose code:

public delegate int ModifyInt(int input);

ModifyInt multiplyByTwo = delegate(int x){
    return x * 2;
};

Lambda Expressions with Multiple Parameters or No Parameters

Use parentheses around the expression to the left of the => operator to indicate multiple parameters.

delegate int ModifyInt(int input1, int input2);
ModifyInt multiplyTwoInts = (x,y) => x * y;

Similarly, an empty set of parentheses indicates that the function does not accept parameters.

delegate string ReturnString();
ReturnString getGreeting = () => "Hello world.";

Lambdas can be emitted both as `Func` and `Expression`

Assuming the following Person class:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

The following lambda:

p => p.Age > 18

Can be passed as an argument to both methods:

public void AsFunc(Func<Person, bool> func)
public void AsExpression(Expression<Func<Person, bool>> expr)

Because the compiler is capable of transforming lambdas both to delegates and Expressions.

Obviously, LINQ providers rely heavily on Expressions (exposed mainly through the IQueryable<T> interface) in order to be able to parse queries and translate them to store queries.

Lambdas for both `Func` and `Action`

Typically lambdas are used for defining simple functions (generally in the context of a linq expression):

var incremented = myEnumerable.Select(x => x + 1);

Here the return is implicit.

However, it is also possible to pass actions as lambdas:

myObservable.Do(x => Console.WriteLine(x));

Passing a Lambda Expression as a Parameter to a Method

List<int> l2 = l1.FindAll(x => x > 6);

Here x => x > 6 is a lambda expression acting as a predicate that makes sure that only elements above 6 are returned.

Put Multiple Statements in a Statement Lambda

Unlike an expression lambda, a statement lambda can contain multiple statements separated by semicolons.

delegate void ModifyInt(int input);

ModifyInt addOneAndTellMe = x =>
{
    int result = x + 1;
    Console.WriteLine(result);
};

Note that the statements are enclosed in braces {}.

Remember that statement lambdas cannot be used to create expression trees.