{
There’s probably a name for this specific approach but in a personal project of late I’ve found a useful pattern for generalizing my exception handling. I write a ExceptionHelper class that takes a variety of high order function style methods to handle my exceptions in a single spot. Here is a somewhat simple form of what I've been doing:
public class ExceptionHelper
{
public static void ExecuteWithSuppress(Action code)
{
try
{
code();
}
catch (Exception ex)
{
// pass and ignore the exception
}
}
public static void ExecuteWithHandler(Action code)
{
try
{
code();
}
catch (Exception ex)
{
Console.WriteLine("An exception occured! Details: \n" + ex.ToString());
}
}
public static void ExecuteWithHandler(Action code, string errorMessage)
{
try
{
code();
}
catch (Exception ex)
{
Console.WriteLine((errorMessage.Length > 0) ? errorMessage : ex.ToString());
}
}
public static void ExecuteWithHandler(Action code, Action onError)
{
try
{
code();
}
catch (Exception ex)
{
if (onError != null)
{
onError();
}
}
}
public static void ExecuteWithHandler(Action code, Action onError, string errorMessage)
{
try
{
code();
}
catch (Exception ex)
{
Console.WriteLine((errorMessage.Length > 0) ? errorMessage : ex.ToString());
if (onError != null)
{
onError();
}
}
}
public static bool ExecuteWithNotificationButIgnore(Action code)
{
bool ret = true;
try
{
code();
}
catch (Exception ex)
{
ret = false;
}
return ret;
}
public static void ExecuteWithLogging<T>(Action code) {
try
{
code();
}
catch (Exception ex)
{
if (ex is T) {
Console.WriteLine("Logging exception " + ex.ToString());
}
}
}
public static void ExecuteWithLogging(Action code, Action<Exception> handles) {
try
{
code();
}
catch (Exception ex)
{
handles(ex);
}
}
}
At this point I use it in a lot of places, here are a few scenarios:
ExecuteWithSuppress(Action code) – code that has a low impact of failure or an expected failure under some conditions. For example, a client of mine once had a legacy database they wanted to me parse a “name” field from. We set up basic heuristics to separate out first and last and so on, but on failure we just returned a blank string.
ExecuteWithHandler(Action code) – you have some generalized exception handling to do something: prompt the user, do logging, etc. ExecuteWithHandler(Action code, Action handler) – you get to pass in the exception handling you want
ExecuteWithHandler(Action code, string errorMessage) – pass a custom error message
ExecuteWithNotificationButIngore(Action code) – try to execute some code but return a boolean to indicate success
ExecuteWithLogging<T>(Action code) – run some code, indicate the types of exceptions to differentiate
ExecuteWithLogging(Action code, Action<Exception> handles) – pass a method to catch be passed the exception that occurs.
The resulting code I write with this pattern, I find pleasant. Here are some examples:
string userName = String.Empty;
ErrorHelper.ExecuteWithSuppress(() => userName = doc.Descendants("Name").First().Value);
return userName;
if (ErrorHelper.ExecuteWithNotificationButIgnore(() =>
{
SendEmail();
}
else
{
// message not delivered, etc, etc.
}
I want it to be absolutely clear that this is not a replacement for try/catch/finally logic where it is warranted. It is simply an alternative that can help to keep code clear and readable. As with many things in software, there is taste involved in when and where something like this is leveraged. But it works well enough for me that I thought I’d share.
2 comments:
Reminds me of a similar pattern that we use from time to time with Python decorators. We create a decorator that uses the given function and arguments to call the function, handling any exceptions that occur as desired.
ie. Something similar to your console writing example would be.
@print_exception
def foo(a, b=None):
...some code..
When an exception occurs in foo, the print_exception decorator would handle it and print to std out.
Hi,
I must say that I really don't like this pattern.
First of all, you catch Exception (not a specific one) and then you do nothing. It's very easy to suppress some important exceptions.
If you have code that throws so many exceptions that you need helpers to handle them, then maybe there is something wrong with the code in the first place.
Imho, it's much better to have some global exception handler that logs unhandled exceptions and to catch only specific exceptions when you exactly know what to do with them.
Maybe you should look at some aspect oriented frameworks and find better ways to handle exceptions globally.
Greetings.
http://codepark.blogspot.com/
Post a Comment