Lambda cheat sheet

A while ago I wrote about all the new language features of C# 3.0 and it occurred to me that I’d left out a chunk about Lambdas. With LINQ being such an important part of C#3.0 that seems like a terrible omission, so I’m going to make up for it now.

The easiest way to think about a lambda is that it is a short form of anonymous methods that were introduced in C#2. However, you can also use lambdas to create expression trees (I’ll come to those in more detail in another post, for the moment, I’ll be concentrate on using lambdas for creating anonymous methods).

Basic Structure

A lambda that looks like this

(i) => 123 + i
^^^ ^^ ^^^^^^^
(1) (2)  (3)

is compiled to an anonymous method

delegate (int i) { return 123+i; }
         ^^^^^^^   ^^^^^^^^^^^^^
           (1)          (3)

The first part of the lambda (1), in the brackets, declares the parameters. The brackets are, incidentally, optional if there is only one parameter. The type is inferred so you don’t have to explicitly declare it as you would have to do with an anonymous method. However, if the compiler cannot infer the parameter type then you will have to declare it explicitly:

(int i) => 123 + i

The second part (2) is pronounced “goes to” and does not really have an equivalent with an anonymous method, although you could argue that it is the equivalent of the delegate keyword.

The third part (3) is the expression or statement. In a lambda expression the return is implicit so it does not need to be declared. It can also contain a number of statements enclosed in separated by semi-colon, but in that case it cannot be used to create expression trees and you must explicitly have a return statement if there is something being returned.

delegate void DisplayAdditionDelegate(int i, int j);

DisplayAdditionDelegate add = (i, j) =>
    { Console.WriteLine("{0} + {1} = {2}", i, j, i+j); };
add(2, 5);
// Output is: 2 + 5 = 7

Framework assistance

The .NET Framework provides a number of predefined generic delegate types that can be used with lambdas in order that is is easy to refer to them and pass them around.

Each of these contains a generic list of parameter types and finally the return type, or if there are no parameters just the return type.

The delegates with a return type are defined as:

public delegate TResult Func<TResult>()
public delegate TResult Func<T, TResult>(T arg)
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2)
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2, T3 arg3)
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)

The delegates without a return type are defined as:

public delegate void Action<T>(T obj)
public delegate void Action<T1, T2>(T arg1, T2 arg2)
public delegate void Action<T1, T2, T3>(T arg1, T2 arg2, T3 arg3)
public delegate void Action<T1, T2, T3, T4>(T arg1, T2 arg2, T3 arg3, T4 arg4)

You can then uses these delegates to represent an appropriate method without having to create a custom delegate type – for most purposes they are quite sufficient.

Outer variables

Outer variables are variables that the lambda can use that are defined in the method that defines the lambda.

int j = 25;
Func<int, int> function = i => 100 + i + j;
j = 75;
int result = function(50);
// result == 225

As you can see in the above example the value of j is not evaluated at the point the lambda is declared, but at the point it is invoked. The lambda is able to keep a reference to j even although it was declared in a different scope. The same is true if the lambda is eventually invoked from a different scope block altogether. For example, if it has been passed out of the method in which it is declared.

The lambda can also change the value of the outer variable. For example:

int j = 6;
Func<int, int> function = i => { j = j * j; return 100 + i + j; };
int result = function(50);
// result == 186
// j == 36

4 Comments

  1. Interesting, but I find using mybool ? “str1”, “str2” Much more useful and not well documented

  2. The Conditional Operator? It seems well documented to me. πŸ™‚ I think it is just not well known about. It is useful for some things, but I’ve seen people use it for things that are way too long and make code look terrible and unreadable.

  3. matt warren says:

    Hi Colin,Nice post, just one thing though, you wrote”Each of these contains a generic list of parameter types and finally the return type, or if there are no parameters just the return type. There are no equivalents without a return type.”Surely that’s not strictly true though, what about “Action”, like the folowing: Action<int> action = i => Console.WriteLine(i); action(5);

  4. Doh! I can’t believe I missed that all this time! Thanks for the correction, I’ve updated the post. πŸ™‚

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s