My last post about the ApplicationException resulted in some questions along the lines of “so, if not ApplicationException, what should I throw instead?” The answer to this question is partially covered by my old post on Exception Throwing and partially by some additional guidelines for creating custom exceptions that did not make it to the original post, but are now included in the FDG book. For your convenience, I included both parts of the guidance below:

Choosing the Right Type of Exception to Throw

After you have decided when you need to throw exceptions, the next step is to pick the right type of exception to throw. This section provides those guidelines.

þ Consider throwing existing exceptions residing in the System namespaces instead of creating custom exception types.

See section 7.3 for detailed usage guidelines of the most common standard exception types.

þ Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exception. Otherwise, throw one of the existing exceptions. See section 7.4 for details on creating custom exceptions.

ý Do not create and throw new exceptions just to have ‘your team's’ exception.

þ Do throw the most specific (the most derived) exception that makes sense.

For example, throw ArgumentNullException and not its base type ArgumentException if a null argument is passed.

Annotation (Jeffrey Richter):

Throwing System.Exception, the base class of all CLS-Compliant exceptions is always the wrong thing to do.

 

Annotation (Brent Rector):

As described in more detail later, catching System.Exception is nearly always the wrong thing to do as well.

Now that you have chosen the correct exception type, you can focus on ensuring that the error message your exception delivers says what you need it to say.

Designing Custom Exceptions

In some cases, it will not be possible to use existing exceptions. In those cases, you’ll need to define custom exceptions. The guidelines in this section provide help on doing that.

ý Avoid deep exception hierarchies. 

þ Do derive exceptions from System.Exception or one of the other common base Exceptions.

þ Do end exception class names with the ‘Exception’ suffix.

þ Do make exceptions serializable. An exception must be serializable to work correctly across application domain and remoting boundaries.

þ Do provide (at least) these common constructors on all exceptions. Make sure the names and types of the parameters are exactly as in the example below.

public class SomeException: Exception, ISerializable {

   public SomeException();

  public SomeException(string message);

  public SomeException(string message, Exception inner);

 

  // this constructor is needed for serialization.

   protected SomeException(SerializationInfo info, StreamingContext context);

}

þ Do report security sensitive information through an override of ToString only after demanding an appropriate permission.

If the permission demand fails, return a string excluding the security sensitive information.

Annotation (Rico Mariani):

Do not store the results of ToString in any generally accessible data structure unless that data structure suitably secures the string from untrusted code.  This advice applies to all strings but since exception strings frequently contain sensitive information (such a file paths) I reiterate the advice here.

þ Do store useful security sensitive information in private exception state. Ensure only trusted code can get the information.

þ Consider providing exception properties for programmatic access to extra information (besides the message string) relevant to the exception.