As I'm sure you've heard, we're not far from .NET 3.5 SP1 which is now in
beta. So it's probably time we got familiar with some of the new features in C# 3.0 including Lambda expressions.
At it's most basic interpretation, a Lambda is just another shorthand way of writing a delegate method. Let's look at how we handled delegates in .NET 1.x using the ThreadPool.QueueUserWorkItem as an example.
class Program
{
public static void Method(object state)
{
Console.WriteLine(state);
}
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(
new WaitCallback(Method),
"Boo from WaitCallback delegate");
}
}
As you can see, the QueueUserWorkItem method expects a delegate of type WaitCallBack. .NET 2.0 introduced a bunch of new shortcuts, including inferred delegates:
ThreadPool.QueueUserWorkItem(
Method,
"Boo from inferred WaitCallback delegate");
And, perhaps more significantly, anonymous delegates:
ThreadPool.QueueUserWorkItem(
delegate(object state) { Console.WriteLine(state); },
"boo from anonymous delegate");
So far, all these methods do exactly the same thing (except that the output passed as the state parameter varies, of course).
Lambda Expressions
If you've seen a lambda before it probably looked something like this (where
strings is an array of String objects).
strings.Where(x => x.StartsWith("b"));
And you'd be forgiven for failing to spot the delegate hiding in there, but in there it is. There are a number of forms of lambda and the one above is shortest, and arguably most confusing at first. Let's look at a longer form of lambda to recreate the QueueUserWorkItem example from above:
ThreadPool.QueueUserWorkItem(
(object state) => Console.WriteLine(state),
"boo from 'verbose' lambda");
Hopefully, the 'delegate' part is slightly clearer now. We have the parameters in parentheses:
(object state) and then the
=> 'operator' which signifies a lambda, followed by the body of the delegate:
Console.WriteLine(state). In this instance, only the return type is inferred which you get with C# 2.0's anonymous delegates. However, the C# 3.0 compiler can even infer the types of the parameters. After all, it knows what signature the QueueUserWorkItem expects. Now our lambda can look like this:
ThreadPool.QueueUserWorkItem(
(state) => Console.WriteLine(state),
"Boo from shorter lambda");
Finally, in cases where your lambda has only one parameter you don't even need to wrap them in parantheses:
ThreadPool.QueueUserWorkItem(
state => Console.WriteLine(state),
"Boo from shortest lambda");
How far you go depends on what you think of the readability of each case. You can of course wrap the whole thing in parentheses if you like and this is common for single parameter bracketless lambdas:
ThreadPool.QueueUserWorkItem(
(state => Console.WriteLine(state)),
"Boo from another lambda");
In the next post we'll explain what's going on in the
strings.Where(x => x.StartsWith("b")) example.