Expect Unique Exceptions

One too common programming practice that irks me when I find it in source code is throwing or catching non-specific exceptions. I believe firmly that it is important to fail fast, and exceptions are a great way to ensure fast-failing code. If you drag out a failure you can hide the initial issue or allow a process to continue after an error has happened. Using non-specific exceptions will also hide information. Failing quickly is important as is being able to respond correctly to an exception and track down the cause.

Steve Smith posted recently saying that one should not throw duplicate exceptions. He gave a great example of where people will check for two different cases and throw duplicate exceptions.

public void Foo(SomeClass someArgument)
{
if(someArgument == null)
{
throw new InvalidArgumentException("someArgument");
}
if(!someArgument.IsValid())
{
throw new InvalidArgumentException("someArgument");
}

// Do Real Work
}

Checking for null as well as custom validity is important, and you want them to be separate cases. The suggestion from Steve is that you give them unique messages or use a more specific exception to allow people to tell what caused the error.

public void Foo(SomeClass someArgument)
{
if(someArgument == null)
{
throw new ArgumentNullException("someArgument");
}
if(!someArgument.IsValid())
{
throw new InvalidArgumentException("someArgument");
}

// Do Real Work
}

public void Bar(SomeClass someArgument)
{
if(someArgument.Quantity < 0)
{
throw new InvalidArgumentException("someArgument",
"Quantity cannot be less than 0. Quantity: " + someArgument.Quantity);
}
if(someArgument.Quantity > 100)
{
throw new InvalidArgumentException("someArgument",
"SomeArgument.Quantity cannot exceed 100. Quantity: " + someArgument.Quantity);
}

// Do Real Work
}

I lean toward using unique exceptions for handling this. It allows for better handling of the result and less duplication of the code. For example in the method listed above instead of using an InvalidArgumentException when the Quanitity is negative, I could use a NegativeSomeClassQuantityException. For the second one I might use an ExceededSomeClassQuanityException with the following resulting code.

public void Bar(SomeClass someArgument)
{
if(someArgument.Quantity < 0)
{
throw new NegativeSomeClassQuantityException("someArgument", someArgument.Quantity);
}
if(someArgument.Quantity > 100)
{
throw new ExceededSomeClassQuantityException("someArgument", someArgument.Quantity);
}

// Do Real Work
}

This is great because my code isn’t concerned with how to format these exceptions. My code just passes the required information via constructor parameters and the exception knows how it should be formatted. The calling code can catch each of these exceptions if it has a special way of handling either one or through the use of polymorphism it can handle both of them.

We want to make sure that we inherit from a relevant exception as well, so we could use the InvalidArgumentException.

public class NegativeSomeClassQuantityException : InvalidArgumentException
{
public NegativeSomeClassQuanitytException(string argumentName, int quantity) :
base(argumentName, "Quantity cannot be less than 0. Quantity: " + someArgument.Quantity)
}

public class ExceededSomeClassQuantityException : InvalidArgumentException
{
public ExceededSomeClassQuantityException(string argumentName, int quantity) :
base(argumentName, "SomeArgument.Quantity cannot exceed 100. Quantity: " + someArgument.Quantity)
}

Comments