Skip Navigation LinksHome > View Post

Delegates and Lambda

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.

Tags: C#

 
Josh Post By Josh Twist
12:23 AM
16 May 2008

» Next Post: Func and Action
« Previous Post: Using Ukadc.Diagnostics with existing TraceSources

Comments are closed for this post.

© 2005 - 2014 Josh Twist - All Rights Reserved.