When .Net was introduced, one of the most powerful language features has been delegates which provide a way to pass around, not only data values, but also chunks of implementation and logic. Consider how often you need to add a button to a web form or windows form and have some code execute when the button is clicked. In Visual Studio, you can simply double-click on the button in the designer and the IDE will generate a new method for you, and wire that method to the event. The generated code contsructs a delegate and passes it to the button so it can be called by the button at the proper time. In effect, it tells the button, "When you're clicked on, execute this chunk of code".
Delegates have come a long way since the 1.0 days. Consider the following code for a Windows Form class. In this example, we'll look at the evolution of the delegate.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//DotNet 1.0 and 1.1 - had to specify the implementation in a separate method
this.button1.Click += new System.EventHandler(this.button1_Click);
//DotNet 2.0 - Anonymous Methods. Can declare implementation inline.
this.button2.Click += delegate
{
MessageBox.Show("Clicked Button 2");
};
//DotNet 3.5 - Declaring implementation inline using Lambda Expressions
this.button3.Click += (sender, e) => MessageBox.Show("Clicked Button 3");
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Clicked Button 1");
}
}
I've created a form in Visual Studio 9 (Orcas), dropped three buttons on it and implemented event handlers using three different syntaxes. If you were to double-click on Button1, you'd get the implemenntation demonstrated for that button, above. A separate method is created and your event handling code is written in that method. This is a bit verbose and anyone reading the code may have to scroll around to follow the picture since the delegate and the method it calls are in two separate places.
For Button2, I've created the delegate using the anonymous method syntax introduced in .Net 2.0. With it, you don't need to declare a separate method containing the implementation. Instead, where the delegate is declared, you can also specify the implementation. This makes the code both more brief and also keeps the delegate declaration and its implementation located together, making the code more readable.
In the latest .Net release, Lambda Expressions were introduced. While the name may sound scary and complicated, they're really nothing more than a third syntax for specifying delegate implementations. As you can see in the implementation for Button3, I've specified the familiar parameter list of (sender, e). Also, I didn't need to specify the types of the parameters though you could if you wanted to. The compiler will figure out the types for us based on the context of the expression. As Scott Guthrie explains in this post, the parameters' types are also known by the intellisense engine so we can get intellisense on the parameters. The parameter list is then followed by a "=>" symbol and finally the implementation itself. Once again, more concise and far more readable than the previously introduced syntax.
I can barely imagine what LINQ queries would look like had the latter two syntaxes not been introduced for delegates (especially the Lambda Expression syntax), but this doesn't mean the improvements are only useable in Linq queries. As I've demonstrated, they are useful and even preferable any time a delegate is required.