posted by Amit Bahree on Tue 27th Apr 2004 05:42 UTC
"Exception Management in .NET, Page 2/3"
Exception Propagation
There are typically three ways, on how to propagate an exception up the chain:
  • Propagate Automatically – here you do not do anything and deliberately ignore the exception. This would cause the control to leave the current code block and move up the stack until an appropriate catch filter is found. If none is found, ultimately the user would see the exception in all its glory (which almost always is not a good idea).
  • Catch and Rethrow – here you typically try to recover from the exception if possible or do some clean up before propagating it up the stack.
  • Catch, Wrap and Rethrow – As an exception moves up the stack, it becomes less relevant. You can wrap the original exception into another one, which is more relevant to the caller.
  • Designing your Exception Class
    First and foremost, if an exception class already exists in the framework, use that instead of creating your own. You should typically only create a new exception for conditions that your code would need to handle and it is not already available either in the framework or an existing application exception hierarchy. A few things to keep in perspective when designing your application hierarchy:

  • The grouping of the exceptions should make sense to the caller of your code.
  • Keep it as flat as possible.
  • Store your hierarchy in one assembly if possible that can be referenced by your application (and its various components). This also helps centralize the management and deployment of your code.
  • Always end your custom exception class with the literal “Exception”.
  • Always provide the three constructors (shown in the example below), in your exception class.
  • Create a base exception class for your application that derives from ApplicationException and all other exceptions derive from that base exception.
  • Include a localized description string in every exception. When the user sees an error message, it is derived from the description string of the exception that was thrown, rather than from the exception class.
  • Use grammatically correct error messages, including ending punctuation.
  • Provide Exception properties for programmatic access. Also include extra information in an exception (in addition to the description string) only when there is a programmatic scenario where the additional information is useful.
  • Return null for extremely common error cases. For example, File.Open returns null if the file is not found, but throws an exception if the file is locked.
  • Throw an InvalidOperationException if a property set or method call is not appropriate given the object's current state.
  • Throw an ArgumentException or a class derived from ArgumentException if bad parameters are passed.
  • The stack trace begins at the statement where the exception is thrown and ends at the catch statement that catches the exception. Be aware of this fact when deciding where to place a throw statement.
  • Use exception builder methods. It is common for a class to throw the same exception from different places in its implementation. To avoid excessive code, use helper methods that create the exception and return it.
  • Clean up intermediate results when throwing an exception as the callers should be able assume that there are no side effects of the exception when thrown.
  • For user-defined exceptions, you must ensure that the metadata for the exceptions is available to code executing remotely, including when exceptions occur across application domains. If you want to be able to remote custom exceptions then use the [Serializable] attribute and add the following constructor: protected YourBaseApplicationException(SerializationInfo info,StreamingContext context) : base(info, context)
  • Sample Base Application Exception:
    public class YourBaseApplicationException : ApplicationException
    {
         // Default constructor
         public YourBaseApplicationException ()
         {
         }

         // Constructor accepting a single string message
         public YourBaseApplicationException (string message) : base(message)
         {
         }

         // Constructor accepting a string message and an
         // inner exception that will be wrapped
         public YourBaseApplicationException(string message,
              Exception inner) : base(message, inner)
         {
         }
    }

    Use Exceptions Wisely
    Like I said earlier, exceptions are very expensive and it is best to use them wisely. There is a fine line in using them the proper way versus the “bad” way. A good example of what not to do which I come across very often is below.
    public IDbConnection Open() {
         try
         {
              Connection = new OracleConnection(this.ODSWebConnectionString);
              Connection.Open();

              return Connection;
         }
         catch(Exception exp)
         {
              throw exp;
         }
    }

    In the example above, the code catches and exception just to rethrow it which adds a lot of overhead for something which does not do anything. In the above example, you should not have the try…catch block as it does not add anything else. If you want to understand all the steps involved (and why this is an expensive operation) refer to the Appendix.

    Table of contents
    1. "Exception Management in .NET, Page 1/3"
    2. "Exception Management in .NET, Page 2/3"
    3. "Exception Management in .NET, Page 3/3"
    e p (0)    25 Comment(s)

    Related Articles

    posted by Thom Holwerda on Fri 13th Jun 2008 18:09, submitted by wakeupneo
    posted by Thom Holwerda on Fri 22nd Feb 2008 09:16, submitted by obsethryl