Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make this exception handling code adhere to the DRY principle?

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;}                  
          }
     }
 } 
like image 308
fin Avatar asked Aug 03 '12 17:08

fin


People also ask

Can you please explain the DRY principle?

"Don't repeat yourself" (DRY) is a principle of software development aimed at reducing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy.

What is the DRY principle in coding?

DRY, which stands for 'don't repeat yourself,' is a principle of software development that aims at reducing the repetition of patterns and code duplication in favor of abstractions and avoiding redundancy.

How do you make sure that your code is capable of handling different error situations?

If you can sense what type of exceptions may arise, create a small separate code to rebound from this state. Be specific about all different exceptions. Depending on your program, these exceptions may hamper your data if not written well. Try using statements that can make error handling for you.

Why is DRY important in coding?

DRY stands for Don't Repeat Yourself and the principle is that there should only ever be one copy of any important piece of information. The reason for this principle is that one copy is much easier to maintain than multiple copies; if the information needs to be changed, there is only one place to change it.


3 Answers

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.

like image 96
McGarnagle Avatar answered Nov 10 '22 11:11

McGarnagle


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);
like image 38
James Avatar answered Nov 10 '22 11:11

James


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.

like image 42
Femaref Avatar answered Nov 10 '22 12:11

Femaref