Reputation: 1303
I have a particular situation where I need to trap exceptions and return an object to the client in place of the exception. I cannot put the exception handling logic at a higher level i.e. wrap Foo within a try clause.
It's best to demonstrate with some sample code. The exception handling logic is clouding the intention of the method and if I have, many methods of similar intent, in the Foo class, I find myself repeating most of the catch logic.
What would be the best technique to wrap the common exception functionality in the code below?
public class Foo
{
public Bar SomeMethodThatCanThrowExcepetion()
{
try
{
return new Bar().Execute();
}
catch(BazException ex)
{
WriteLogMessage(ex, Bar.ErrorCode);
return new Bar() { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode;}
}
}
public Baz SomeMethodThatCanThrowExcepetion(SomeObject stuff)
{
try
{
return new Baz(stuff).Execute();
}
catch(BazException ex)
{
WriteLogMessage(ex, Baz.ErrorCode);
return new Baz() { ErrorMessage = ex.Message, ErrorCode = Baz.ErrorCode;}
}
}
}
Upvotes: 8
Views: 512
Reputation: 7543
How about a base class:
public class ErrorCapable {
public string ErrorMessage { set; get; }
public int ErrorCode { set; get; }
public static ErrorCapable<T> Oops(Exception exc) where T : ErrorCapable, new() {
// Code for logging error here
return new T() { ErrorMessage = exc.Message, ErrorCode = exc.ErrorCode };
}
}
public class Bar : ErrorCapable {
//...
}
public class Baz : ErrorCapable {
//...
}
Then in the catch, just use, for example:
return ErrorCapable.Oops<Bar>(ex);
Upvotes: 5
Reputation: 102793
Updated per Lee's comment
One possibility is to use a generic helper method. Something like this:
T TryExecute<T>(Func<T> action, int ErrorCode)
{
try
{
return action();
}
catch (Exception ex)
{
result = Activator.CreateInstance<T>();
typeof(T).GetProperty("ErrorMessage").SetValue(result, ex.Message, null);
typeof(T).GetProperty("ErrorCode").SetValue(result, ErrorCode, null);
return result;
}
return result;
}
If you can modify Bar and Baz, then you could improve this by placing a requirement on T:
public interface IError
{
public string ErrorMessage { get; set; }
public int ErrorCode { get; set; }
}
T TryExecute<T>(Func<T> action, int ErrorCode) where T : IError
{
try
{
return action();
}
catch (Exception ex)
{
result = Activator.CreateInstance<T>();
result.ErrorMessage = ex.Message;
result.ErrorCode = ErrorCode;
return result;
}
}
Then you'd use:
return TryExecute<Bar>(new Bar().Execute, Bar.ErrorCode);
And:
return TryExecute<Baz>(new Baz(stuff).Execute, Baz.ErrorCode);
That may or may not be an over-abstraction for your particular design; the devil is in the details.
Upvotes: 5
Reputation: 144206
I think the best you can do is something like:
public T TryOrDefault<T>(Func<T> act, int errorCode, Func<BazException, T> onError)
{
try
{
return act;
}
catch(BazException ex)
{
WriteLogMessage(ex, errorCode);
return onError(ex);
}
}
then you can write your other methods in terms of it:
public Bar SomeMethodThatCanThrowException()
{
Bar b = new Bar();
return ExecOrDefault(() => b.Execute(), Bar.ErrorCode, ex => new Bar { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode });
}
Upvotes: 2
Reputation: 61477
Do you really need the explicit logging in every method? Instead of having the exception logic in every method, have one handler in your Main
method of the program and handle the exceptions generically.
Also, you don't need to return an arbitrary object from a catch block should you really need the logging there, simply use throw;
to let it wander up the stack.
Upvotes: 2