Monday 28 March 2005 — This is close to 20 years old. Be careful.
Continuing my education in C#, I don’t understand what happens to exceptions in event handlers. For the most part, when I register an event handler for a UI event (like button click), if the handler throws an exception, I get a detailed dialog box showing what happened. But for some events, the exception is eaten silently. One of my strongest passions when coding is to know what is going on under the covers, and to be absolutely sure that error conditions are at the very least visible.
I’m starting to get the hang of events and delegates. It isn’t yet another language for me, still a foreign language. But I figured there ought to be a way to write a delegate wrapper, so that I could take an event registration like this:
button1.Click += new EventHandler(button1_Click);
and using some yet-to-be-written class, make it look like this:
button1.Click += new WrappedHandler(new EventHandler(button1_Click));
where WrappedHandler would call the event handler passed into it, but inside a try-catch block, so that exceptions could be displayed.
I had to take a few stabs at it, and I ended up with three “new”s rather than the two I thought I would need, but here’s something that works:
public class WrappedHandler
{
private EventHandler handler;
public WrappedHandler(EventHandler handler)
{
this.handler += handler;
}
public void Handler(object sender, EventArgs e)
{
try
{
handler(sender, e);
}
catch (Exception ex)
{
// Our handler threw an exception.
// Show it.
MessageBox.Show("Exception: " + ex.ToString());
// Then re-throw it.
throw;
}
}
}
Now the event handler can be registered like this:
button1.Click +=
new EventHandler(
new WrappedHandler(
new EventHandler(
button1_Click
)
).Handler
);
Is this the simplest it could be? Did I miss a left turn a half mile back?
BTW: as I was making a new tiny project to experiment with this, I noticed that all of the event handlers were nicely reporting exceptions. My real project still has exceptions which aren’t being reported. I’ll have to track down whether it’s because they are different handlers, or because of the third-party controls we’re using, or even because my predecessor is eating exceptions somewhere. Fun fun.
Comments
But these are great pointers guys, thanks!
Call "base" if you want to re-use some of the base class implementation by invoking one of its methods.
You're right, EventHandler is sealed, which prevents inheriting it. That's a shame :-(
http://www.codinghorror.com/blog/archives/000216.html
However this can be subtle. For example, if your app supports drag and drop via the provided .NET mechanisms.. well, that's a COM operation behind the scenes-- so exceptions in the draggin' will be silently eaten. Really nasty.
I ended up going this route, adding an
ErrorWrapper
method on my base class which wraps the handler in a lamba: (This is a .NET MAUI project)And an async version for any handlers that have awaits inside them:
Usage:
Add a comment: