Using Lambdas as Event Handlers

Of all the new features in C# 3.0, Lambda expressions have to be one of my favourites.

One non-obvious way that they can be used is as event handlers, in just the way that anonymous delegates could be.

Consider these examples, handling the AfterExpand method of a WinForms TreeView.

Original code, from the era of C# 2.0:

[csharp]
treeView.AfterExpand +=
new TreeViewEventHandler(
delegate(object o, TreeViewEventArgs t)
{
t.Node.ImageIndex = (int)FolderIconEnum.open;
t.Node.SelectedImageIndex = (int)FolderIconEnum.open;
}
);
[/csharp]

First, lets swap out the delegate for a lambda expression:

[csharp]
treeView.AfterExpand +=
new TreeViewEventHandler(
(object o, TreeViewEventArgs t) =>
{
t.Node.ImageIndex = (int) FolderIconEnum.open;
t.Node.SelectedImageIndex = (int) FolderIconEnum.open;
}
);
[/csharp]

The C# compiler is willing to infer the new TreeViewEventHandler(), so we can leave it out:

[csharp]
treeView.AfterExpand +=
(object o, TreeViewEventArgs t) =>
{
t.Node.ImageIndex = (int) FolderIconEnum.open;
t.Node.SelectedImageIndex = (int) FolderIconEnum.open;
};
[/csharp]

Now, the types of the arguments to the lamda expression can be inferred:

[csharp]
treeView.AfterExpand +=
(o, t) =>
{
t.Node.ImageIndex = (int) FolderIconEnum.open;
t.Node.SelectedImageIndex = (int) FolderIconEnum.open;
};
[/csharp]

Simple, clean and easy to read … well, once you’re used to it, anyway.

Blog Tags: 

Comments

Overall, I agree with you,

Overall, I agree with you, but when using lambda event handlers I feel there is also a whole lot of potential for making difficult to read code, even for programmers who are used to the syntax.

As such, I personally stick to a couple simple guidelines:

1) Keep lambda event handlers short; preferably only two or three lines. If the event handler is more lines than that, split it out into it's own method. This goes for most uses of lambda actually, not just event handlers (where possible).

2) Define all lambda event handlers within a single method, with ideally no code between each definition:

treeView.AfterExpand +=
(o, t) =>
{
...
...
};
treeView.DrawNode +=
(o, d) =>
{
...
...
};

treeView.Layout += new LayoutEventHandler(treeView_Layout);

Having full blown functions defined within methods, and having definitions spread throughout the class file can make for some really difficult to understand code. This all, of course, goes for other platforms that allow code like this (JavaScript, ActionScript).

Keeping it Simple

Henry, you're 100% correct - I'd rate you even higher if that were mathematically possible. ;-)

In my own code, I tend to keep lambda event handlers to just one line - any longer, and I break things out into their own method. Frequently, though I'll sill use a lambda, just so that the signature of my method doesn't need to conform to the signature of the event handler.

To illustrate:

[csharp]
public void Setup()
{
...
mBoundsEditor = new BoundsEditor();
mBoundsEditor.PropertyChanged += (s,a) => Changed();
...
}

private void Changed()
{
...
}
[/csharp]

Without the lambda expression, Changed() would need to accept parameter that aren't relevant to its' job.

Thanks again for the comment.