Wednesday, January 27, 2010
MSDN Premium Azure accounts
Delegates and Lambda Expressions
Introduction
Delegates and lambdas are a very important construct to programmers. They follow a very linear evolution from framework 1.1 to 3.5. In this post we will be taking a look at delegates and lambdas’ and some of their uses. First of all, some logistics. The code samples you will see are from an awesome tool called LINQPad. It was written by Joseph Albahari and can be found here. This tool allows you to practice writing delegates, lambda expressions and LINQ statements without using Visual Studio. Check it out when you get a chance. It is a valuable tool in any developer’s arsenal.
Delegates in the 1.1 world
Delegates are a variable that points to a method and there are three kinds of delegates.
- Predicate which returns a true or false.
- Action which is basically a void method.
- Function that returns some value.
Now, let’s take a look at some code. In this sample we will define a delegate, assign it to a variable and use it as an action type to send out a simple test message.
void Main()
{
ProgressReporter p = Writers.WriteProgressToConsole;
p(8);
}
public delegate void ProgressReporter(int PercentComplete);
public static class Writers
{
public static void WriteProgressToConsole(int PercentComplete)
{
Console.WriteLine(String.Format("Percent from console = {0}", PercentComplete));
}
}
Here we are defining a delegate ProgressReporter that takes an integer as parameter and returns nothing. The variable p in the main method is declared as this type. This variable can be assigned to any method the matches the signature of the delegate, in our case WriteProgressToConsole. When the line p(8) is invoked, the execution will pass to the WriteProgressToConsole method and print the line to the console. The code here works fine but is a bit verbose. You need a separate class for the function or functions you want to run, you must define the delegate separately and things can get kind of confusing if you are using a lot of delegates. Let see how 2.0 started to improve this.
Delegates in framework 2.0
In 2.0, a new way of working with delegates was introduced called the anonymous delegate. No longer do we have to declare a delegate and the method that it pointed to in separate classes. In this example we will use a predicate delegate to find a list of even integers from a larger list of integers.
void Main()
{
List<int> numbers = new List<int>{1,2,3,4,5,6,7,8,9};
List<int> evens = numbers.FindAll(delegate(int i) { return i % 2 == 0;});
evens.Dump(); //this is an extension method used in LINQPad to output the results
}
In this snippet, we are declaring the delegate within the same line as the list. There is no need for a delegate declaration, a method that matches that signature, or a variable of type delegate pointing to that method. Behind the scenes however, the framework is creating a delegate and doing exactly what we would have if we had named it.
Lambda Expressions
Framework version 3.5 saw Microsoft shorten the syntax of delegates even more. They called this shorten syntax lambda expressions. Taking the example above, we will convert it to a lambda expression.
- Remove the word delegate. numbers.FindAll((int i) { return i % 2 == 0;});
- Remove the parameter’s parentheses and type. numbers.FindAll(i { return i % 2 == 0;});
- Add the lambda symbol “=>” after the parameter. numbers.FindAll(i => { return i % 2 == 0;});
- Finally remove the braces and the word return. numbers.FindAll(i => i % 2 == 0);
So the lambda expression is “i => i % 2 == 0”. Now if you have 0 or more than 1 parameter you must leave the parentheses and if you have more than 1 command, you still need the braces.
Let’s take a peek at the IL for both these statements
Anonymous delegate
IL_0053: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_0058: brtrue.s IL_006D
IL_005A: ldnull
IL_005B: ldftn UserQuery.<Main>b__1
IL_0061: newobj System.Predicate<System.Int32>..ctor
IL_0066: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_006B: br.s IL_006D
IL_006D: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate3
IL_0072: callvirt System.Collections.Generic.List<System.Int32>.FindAll
Lambda Expression
IL_0080: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_0085: brtrue.s IL_009A
IL_0087: ldnull
IL_0088: ldftn UserQuery.<Main>b__2
IL_008E: newobj System.Predicate<System.Int32>..ctor
IL_0093: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_0098: br.s IL_009A
IL_009A: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate4
IL_009F: callvirt System.Collections.Generic.List<System.Int32>.FindAll
Pretty much (ok exactly) the same code.
Conclusions
So we can see that how the syntax for defining delegates has evolved from 1.1 to 3.5 today. There has not been any change in the functionality of delegates, we are just able to write them more succinctly and hopefully that will encourage us to use them more. As developers move to 3.5 and LINQ, they will find that using Lambda expressions is essential for learning LINQ and producing more readable code.
Tuesday, January 12, 2010
Upcoming Silverlight 4 talk: January 19
The fun starts at 6:30. See you there!

