Practical .NET
Integrating Lambda Expressions and Events
Using lambda expressions is a more compact way of wiring up events in both C# and Visual Basic. It also provides a way of passing parameters to an event without having to redefine the event's parameters.
One disadvantage of Visual Basic is that it provides such a clean way of integrating code with events at design time by using the Handles clause:
Protected Sub Page_Load(sender As Object, e As System.EventArgs) _
Handles Me.Load
End Sub
That's a disadvantage because VB developers may never become familiar with the syntax that allows you to dynamically wire up an event at runtime. C# developers are familiar with that syntax from the start of their careers, because it's the only code-based syntax available. However, like C#, VB does provide a way to dynamically tie methods to events.
In C# 3.0 or later, the code to dynamically wire up an event (in this case the Load event of an object referred to by Page) looks like this:
Page.Load += SomeMethod;
In VB, the equivalent operation uses the AddHandler keyword to dynamically tie a method to an event:
AddHandler Page.Load, AddressOf SomeMethod
In both cases, the code to wire up the event goes in one spot and the method goes in another. The result is that the two parts of the event (the wire up code and the event handling code) can end up being widely separated in the code file. It's also overkill to set up the event handler method and give it a name—event handler methods are typically used in exactly one place: when called by the event. They don't really need names.
Wiring Up Events with Lambda Expressions
To reduce your coding overhead (and save some scrolling up and down in your editor), you can use lambda expressions to tie event handling code to an event and do it all in one place. In addition to putting the "event handler" code with the "wire up" code, you save yourself some additional typing because lambda expressions assume implicit data typing. That means you don't have to figure out the data type of the event's e parameter—the compiler will do it for you.
The same wire up code that I showed before would look like this in C# if used a lambda expression:
this.Load += (s, ev) =>
{
HtmlMeta hma = new HtmlMeta();
hma.Name = "viewport";
hma.Content = "width=device-width";
this.Header.Controls.Add(hma);
};
And here's how it would look in VB:
AddHandler Me.Load,
Sub(s, ev)
Dim hma As New HtmlMeta
hma.Name = "viewport"
hma.Content = "width=device-width"
Me.Header.Controls.Add(hma)
End Sub
Captured Variables
Lambda expressions also give you the ability to capture variables, a tool which can reduce the need to define global variables or set up new classes that inherit from System.EventArgs to pass as parameters to an event. A captured variable is any variable within scope when the lambda expression is defined. That variable will continue to be accessible to the code in the lambda expression when the lambda expression executes.
In this example, for instance, the variable MetaText is defined in the method that wires up the lambda expression. The lambda expression then uses that variable within its body in VB:
Dim MetaText As String = "width=device-width"
AddHandler Me.Load, Sub(s, ev)
Dim hma As New HtmlMeta
hma.Name = "viewport"
hma.Content = MetaText
Me.Header.Controls.Add(hma)
End Sub
And here, in C#:
string MetaText = "width=device-width";
this.Load += (s, ev) =>
{
HtmlMeta hma = new HtmlMeta();
hma.Name = "viewport";
hma.Content = MetaText;
this.Header.Controls.Add(hma);
};
When the lambda expression executes it will still be able to access the MetaText property. However, the MetaText variable will only be accessible inside of the lambda expression (and the method that defined the expression, of course). Effectively, the captured variable is local to the two methods and provides a private way for the original code to communicate with the lambda expression without redefining the parameters for the event or declaring a class-level variable.
There's one major caveat with using lambda expressions to wire up an event. For all intents and purposes, it's impossible to "unwire" a lambda expression from an event. Really, the only way to do that is to store the lambda expression in a delegate and pass the delegate to the event. At this point the legacy syntax (AddHandler in VB, += in C#) is both simpler and easier. Since you can't "unwire" a lambda expression, that also means that any captured variables probably won't be disposed of until your application shuts down—something to bear in mind if the captured variable soaks up a lot of resources.
With that one caveat (and how often do you need to unwire events?), the lambda syntax provides a convenient and compact way to wire up events with the ability to provide a pseudo-local parameter to the event.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.