As a sweeping generalisation, I’ve found that developers who are really proficient with delegates / anonymous delegates seem to have a bit of an adverse reaction to seeing the lambda syntax in C# .NET 3.5. Luckily I’m proficient with very little, so the transition was easy for me :). This is a post to try and make the transition easier for people more competent than me :).
From delegates to lambdas
Say I have a Widget
class, which just contains a Name
and a WeightInGrams
.
public class Widget { public Widget(string name, int weightInGrams) { Name = name; WeightInGrams = weightInGrams; } public string Name { get; set; } public int WeightInGrams { get; set; } } }
Now we want to search through an array of these and find how many are under 300 grams. Why? Er, why not? We’ll use Array.FindAll
to do this old skool (as opposed to fancy LINQy stuff like using Where()
). FindAll
takes an array of type T
and a Predicate<T>
, which is a delegate that takes a T
and returns a bool
indicating whether the predicate has been matched.
[TestFixture] public class LambdaTests { [Test] public void SearchArrayUsingDelegate() { var widgets = SixWidgetsFrom100GramsTo600Grams(); var widgets300GramsOrLess = Array.FindAll(widgets, Weighs300GramsOrLess); Assert.That(widgets300GramsOrLess.Length, Is.EqualTo(NumberOfWidgets300GramsOrLess)); } private bool Weighs300GramsOrLess(Widget widget) { return widget.WeightInGrams <= 300; } private const int NumberOfWidgets300GramsOrLess = 3; static Widget[] SixWidgetsFrom100GramsTo600Grams() { return new[] { new Widget("W1", 100), new Widget("W2", 200), new Widget("W3", 300), new Widget("W4", 400), new Widget("W5", 500), new Widget("W6", 600) }; } }
As of .NET 2.0 we can use an anonymous delegate to do this inline:
[Test] public void SearchArrayUsingAnonymousDelegate() { var widgets = SixWidgetsFrom100GramsTo600Grams(); var widgets300GramsOrLess = Array.FindAll(widgets, delegate(Widget widget) { return widget.WeightInGrams <= 300; }); Assert.That(widgets300GramsOrLess.Length, Is.EqualTo(NumberOfWidgets300GramsOrLess)); }
As of .NET 3.5 we have lambda syntax, which provides a terser way of expressing our predicate function:
[Test] public void SearchArrayUsingLambda() { var widgets = SixWidgetsFrom100GramsTo600Grams(); var widgets300GramsOrLess = Array.FindAll(widgets, widget => widget.WeightInGrams <= 300); Assert.That(widgets300GramsOrLess.Length, Is.EqualTo(NumberOfWidgets300GramsOrLess)); }
Clear as mud? Let’s have a closer look at how we convert from delegate to a lambda expression.
//Original delegate: delegate(Widget widget) { return widget.WeightInGrams <= 300; } //Drop the "delegate" keyword, and add a funky "=>" operator, which goes by all sorts of creative names :) (Widget widget) => { return widget.WeightInGrams <= 300; } //The C# 3.0 compiler has type inference, so we can also drop the argument type and let the compiler figure it out. //If we have a single statement to the right of the "=>" operator, this will be returned from the function, //so we can also drop the braces, end-of-statement semicolon and the explicit return. widget => widget.WeightInGrams <= 300
So what’s the difference between our anonymous delegate and our lambda expression? In this example, absolutely nothing other than a terser (and somewhat addictive IMO) syntax. Let’s compare the generated code for both just to prove this:
[CompilerGenerated] private static bool <SearchArrayUsingAnonymousDelegate>b__0(Widget widget) { return (widget.WeightInGrams <= 300); } [CompilerGenerated] private static bool <SearchArrayUsingLambda>b__2(Widget widget) { return (widget.WeightInGrams <= 300); }
So based on this example anonymous delegates and lambdas are exactly the same, it’s just a matter of getting used to writing a bit less noise code. :)
Exactly the same, except when they’re different…
Of course there’s a catch. Actually, I can think of two, and they both relate to expression trees. To support a lot of LINQ magic, lambda expressions can be converted to expression trees at compile time. An expression tree is basically just a bunch of objects representing each part of the lambda expression. A query provider, like the one provided by LINQ to SQL, can then process the expression tree and execute the expression in a different way, say, by converting it to TSQL and running it against database.
To get the compiler to generate an expression tree from a lambda expression we just need to specify the type differently:
Predicate<Widget> lambda = widget => widget.WeightInGrams <= 300; Expression<Predicate<Widget>> expressionTree = widget => widget.WeightInGrams <= 300;
So how does this relate to differentiating anonymous delegates and lambdas?
//Compiles fine: Expression<Predicate<Widget>> expressionTree = widget => widget.WeightInGrams <= 300; //WON'T COMPILE: Expression<Predicate<Widget>> expressionTree = delegate(Widget widget) { return widget.WeightInGrams <= 300; }; /* error CS1946: An anonymous method expression cannot be converted to an expression tree */
As you can see from the code sample above, the compiler will simply refuse to convert the delegate form to an expression tree. So the way the compiler handles the two are quite different as soon as you introduce expression trees. I also mentioned a second catch. Take a look at this modification of the previous example:
//WON'T COMPILE: Expression<Predicate<Widget>> expressionTree = widget => { return widget.WeightInGrams <= 300; }; /* error CS0834: A lambda expression with a statement body cannot be converted to an expression tree */
This second catch is that there is actually a difference between lambda expressions and lambda statements. A lambda statement contains braces and a function body, and can potentially have multiple lines like a standard delegate. A lambda expression is the single line with an implicit return. So in our original, Array-searching example, the following two statements are actually are different if you are trying to assign them to expression trees.
//Lambda statement widget => { return widget.WeightInGrams <= 300; } //Lambda expression widget => widget.WeightInGrams <= 300
Aside: In case you were wondering, here is the expression tree generated by the compiler for the widget => widget.WeightInGrams <= 300
lambda expression, care of Reflector:
ParameterExpression CS$0$0000; Expression<Predicate<Widget>> expressionTree = Expression.Lambda<Predicate<Widget>>( Expression.LessThanOrEqual( Expression.Property( CS$0$0000 = Expression.Parameter(typeof(Widget), "widget"), (MethodInfo) methodof(Widget.get_WeightInGrams)), Expression.Constant(300, typeof(int))), new ParameterExpression[] { CS$0$0000 } );
Conclusion
So in conclusion, lambdas are simply, for most intents and purposes, a neater syntax for defining delegates.
//Delegate: delegate(Widget widget) { return widget.WeightInGrams <= 300; } //Drop the delegate and add the "=>" operator to get a lambda statement (Widget widget) => { return widget.WeightInGrams <= 300; } //Use type inference and implicit return to get a lambda expression widget => widget.WeightInGrams <= 300
The only differences that can bite you are when you are dealing with expression trees, either explicitly via the Expression<>
type, or implicitly by using the LINQ operators. Hope this helps, or at least has caused no significant damage to your understanding of lambdas :)