Lambda Expressions in C#
C# 3.0
introduces a new feature called lambda expressions. While this is not a
revolutionary thing, it opens up a plethora of new possibilities for .Net
programming. This post aims to introduce lambda expressions by providing a backgrounder,
looking into its syntax and providing examples along the way.
A Little
Bit of History
With the
release of C# 2.0, came anonymous methods. For those of you who don’t know it,
anonymous methods allow developers to write a block of code in places where a
delegate is expected. Prior to this, developers are required to explicitly
declare methods and attach them to delegates.
To give you
a clearer picture, here’s how one will write a very simple add delegate in
pre-2.0 C#.
// EXAMPLE 1delegate int BinaryExpression( int x, int y);
static int addFunction(int x, int y)
{
return x + y;
}
static void Main(string[] args)
{
BinaryExpression add = new BinaryExpression( addFunction );
Console.WriteLine( add(4, 2) );
}
With
anonymous methods you can easily bind the body of addFunction to a named
delegate
// EXAMPLE 2
delegate int BinaryExpression( int x, int y);
static void Main(string[] args)
{
BinaryExpression add = delegate(int x,int y)
{
return x + y;
};
Console.WriteLine( add(4, 2) );
}
Lambda
expressions offer an even more clever alternative to this. Just look at the
example below.
// EXAMPLE 3
delegate int BinaryExpression( int x, int y);
static void Main(string[] args)
{
BinaryExpression add = (x, y) => x + y;
Console.WriteLine( add(4, 2) );
}Before Anything
Else…
Let’s take
a look at the lambda expression syntax:
It follows
the form (parameter-list) => expression; where expression can be any C# expression or a
block of code. Just like anonymous methods you can use a lambda expression in
place of a delegate. Below are some sample lambda expressions and their corresponding
delegates.
// assigns to void D(User u)
// Explicitly typed parameter
(User u) => Console.WriteLine(u.Username.ToUpper())
// assigns to bool D(User u)
// Implicitly typed parameter
(u) => u.Username == “User1”
// assigns to int D(int x, int y)
// Explicitly typed parameter
(int x, int y) => x + y
// assigns to int D(int x, int y)
// Implicitly typed parameter
// Uses a block instead of an expression
(x, y) => { return x + y; }As you see from the above example, lambda expressions provide
a little bit of magic in that it can infer the parameter type from the signature
of the delegate it is assigned to.
Func’dafied
You might be thinking by now “WTF! I still have to declare those delegates?”.
Well, not really. Lucky for us C# 3.0 provides a set of generic delegates at
our disposal. Enter the Func delegate type in its different forms.
public delegate RT Func<RT>();
public delegate RT Func<T0, RT>(T0 a0);
public delegate RT Func<T0, T1, RT>(T0 a0, T1 a1);
public delegate RT Func<T0, T1, T2, RT>(T0 a0, T1 a1, T2 a2);
public delegate RT Func<T0, T1, T2, T3, RT>(T0 a0, T1 a1, T2 a2, T3 a3);
The only thing you need to remember
here is that the last generic parameter is the return value.
So going
back to example 3, we can now write it as.
// EXAMPLE 3.1
static void Main(string[] args)
{
Func<int,int,int> add = (x, y) => x + y;
Console.WriteLine( add(4, 2) );
}
Of course there will be times when this set of Func’s won’t
satisfy your need. Like when you need a delegate signature that has more than 3
parameters or takes a ref or out as an argument. This is when you need to
manually create a delegate type.
Resources
C# 3.0 Specification - http://download.microsoft.com/download/9/5/0/9503e33e-fde6-4aed-b5d0-ffe749822f1b/csharp%203.0%20specification.doc
Linq May 2006 CTP - http://www.microsoft.com/downloads/details.aspx?familyid=1e902c21-340c-4d13-9f04-70eb5e3dceea&displaylang=en
Linq/C# 3.0 Learning Guide - http://www.theserverside.net/tt/articles/showarticle.tss?id=CsharpLINQLearningGuide2007