Raising events in C# that ignore exceptions raised by handlers
One of my pet peeves with raising events in C# is the fact that an exception in an event handler will break my code, and possibly prevent other handlers from being called, if the broken one happened to get called first; In most cases my code couldn't care less if somebody else's code that's listening to its events is broken.
I created an extension method that catches exceptions:
public static void Raise(this EventHandler eh, object sender, EventArgs e)
{
if (eh == null)
return;
try
{
eh(sender, e);
}
catch { }
}
Although this does mean my code carries on regardless, this method doesn't stop a first event handler throwing an exception and preventing second and subsequent handlers being notified of the event. I'm looking into a way of iterating through GetInvocationList to wrap each individual event handler in it's own try/catch, but this seems inefficient, and I'm not certain of the best way to do it, or even if I should be.
Also, I'm really not comfortable simply ignoring the exception here (and neither's FxCop/Resha开发者_如何学Crper for that matter); realistically what should happen to the exception in this case?
What if you did something like this?
public static void Raise(this EventHandler eh, object sender, EventArgs e)
{
if (eh == null)
return;
foreach(var handler in eh.GetInvocationList().Cast<EventHandler>())
{
try
{
handler(sender, e);
}
catch { }
}
}
You should only trap those exceptions you can handle. For example you might be accessing a file and not have sufficient privileges. If you know this can happen occasionally and all that needs to happen is that the case is logged then trap that exception alone.
If your code can't handle the exception then don't trap it.
It's an exceptional circumstance so there's a good chance the other event handlers won't be able to "do their stuff" either, so let it propagate to a level where it can be handled safely.
If the event handler didn't catch the exception, I don't see any good way you can handle the exception in the class throwing the event. You don't have any context to know what the handler is doing. It's safest to let the app crash hard in this case, as you have no idea what side effects the other event handler may have caused that could destabilize your application. The lesson here is that event handlers must be robust (handle their own exceptions), as classes that fire events should never catch exceptions thrown by the handlers.
A simple but important rule:
Every defect in code should be as lethal as possible as early as possible.
In this way, the bugs are found and fixed, and the software grows ever stronger. What the others are saying is correct; never catch an exception that you don't expect and know how to deal with.
精彩评论