broersa
broersa

Reputation: 1736

How to bubble/handle C# exceptions in a library implementation

What is the best way to bubble up exceptions from a library? When I implement an interface is it a good or bad practice to bug the calling party with exceptions that go about my implementation details? I have the following implementation where every implementation error is hidden away from the calling party. It looks to me as the cleanest way of implementing separation of concerns. But I read everywhere that you need to bubble up the exceptions untouched.

public class OneException : Exception
{
    public OneException()
    {
    }

    public OneException(string message): base(message)
    {
    }

    public OneException(string message, Exception innerException)
      : base(message, innerException)
    {
    }
}

And my library implementation:

public class MyLib : IMyLib
{
    public int Divide(int a, int b)
    {
        try
        {
            if (b == 1) throw new OneException();
            return a / b;
        }
        catch (OneException e)
        {
            throw new ApplicationException("Please do not divide by 1", e);
        }
        catch (Exception e) // divide by zero and others
        {
            throw new ApplicationException("Oops", e);
        }
    }
}

Upvotes: 3

Views: 3012

Answers (7)

s.ermakovich
s.ermakovich

Reputation: 2674

Choosing a right strategy for exception bubbling depends on two main factors:

  1. Do you want to provide as much details about exception context to caller, as possible?
  2. Do you want to hide sensitive exception data from caller?

If you want to provide more details about exception context, wrapping an exception into some more specific exception is a good strategy. The most obvious example here are business exceptions.

If you want to hide sensitive data from exception, you may consider replacing an exception. This approach is commonly used in services, when calling party is not trusted.

NOTE: You should never "swallow" exceptions, unless it's not a part of a normal program flow.

Upvotes: 2

Peter Gluck
Peter Gluck

Reputation: 8236

In keeping with the Single Responsibility Principle, you should take care of things that your library is supposed to do (if possible). Otherwise, you should let the caller deal with it.

In your example, you correctly throw a divide-by-zero exception. Handling this is not the responsibility of your library (unless you advertised it as a "safe" divide method). The error resulted from incorrect client inputs, so it should be the client that handles it.

Your OneException, however, would be an unusual exception to throw. Why can't the client divide by one? It certainly causes no harm. This is presumably a contrived example, but you should not throw exceptions unless there really is a problem that can't be resolved internally. If someone wants to divide by one, why shouldn't they be allowed to do it?

Good exception handling will notify clients of problems with their inputs and/or system failures, not errors in your logic.

Upvotes: 3

user1088520
user1088520

Reputation:

Both exceptions are covered by the system. For the case of b = 1 use the ArgumentOurOfRange exception and for the case of b = 0 use the DivideByZeroException. So for your very simple sample library there is no need to create additional exceptions (it's not a good practice). Throwing an exception immediately of not is a matter of requirements. In most cases (good practice) you throw the exceptions that can be handled by the caller using try/catch(/finally).

Upvotes: 1

slugster
slugster

Reputation: 49965

Ask yourself these questions:

  • as the developer, what do you want the consumer (caller) to know about your library?

  • as the consumer, what would you want if an error occurred?

You should only start publicising your own types of exceptions if the standard .Net ones are insufficient for the purpose. An example of this is COM related errors - you may want to create custom exceptions for specific error conditions as a way of avoiding throwing COMExceptions with special numbers embedded in them.

I would say that the OneException in your example is a waste of time - why throw, catch and then wrap and rethrow as a standard exception? Why not just throw an ApplicationException to begin with? This is bordering on using exceptions to control program flow, which is an anti-pattern.

Upvotes: 1

Ebad Masood
Ebad Masood

Reputation: 2379

Try logging the exceptions, it is always a good practice. In this way, the client would actually know what went wrong.

Upvotes: 1

Habib
Habib

Reputation: 223422

It depends. If you want to handle an exception and raise a customized exception due to some business rule then sure handle the exception and either log it or raise a new customized exception, like in your example code, where you are raising an exception for divide by 1.

Another example could be, if you are entering data in a table and your get Primary key constraint exception, you can either catch the exception and raise your own customized exception according to your library specifications, or you can leave the exception as it is, to be handled in the calling code.

Handling exception in the library could be helpful, if you are maintaining an internal error/exception log. You can log the exception and then throw it so that it can bubble up to the calling code. But IMHO if you are neither logging or raising customized exception, its better to leave the exception untouched so that it can be handled in the calling code

Upvotes: 1

Jens H
Jens H

Reputation: 4632

As a general rule, only handle those exception that you can handle.

In your library implementation you catch the different exceptions OneException and Exception and rethrow it as ApplicationException. I would consider this a bad practice because you completely hide the meaning of the original error.

How should the client code using your library Divide() method know what exactly happened if the only exception that bubbles up is a generic ApplicationException that gives no clue about the cause?

What you do here is throw an exception, catch it within the same method and rethrow a different exception.

Let the exception bubble up to the client code so that the client can decide for himself how it wants to handle it - or if at all.

Upvotes: 1

Related Questions