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/.

comments powered by Disqus

Featured

  • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

    New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

  • Naive Bayes Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

Subscribe on YouTube

Upcoming Training Events