Rethrowing Exceptions in .NET

By on 9/13/2008

Wow, I finally came across a good reason to rethrow exceptions using the "throw ex" syntax instead of just "throw".  For those of you who don't know, when you have a try/catch block, you have the option of rethrowing the exception so that it may be handled further up the call stack.  The most common reason you might want to do this is for error logging ... so you can log the error, and then let someone else worry about the exception.

try
{
    // some exception to happen here
}
catch(Exception ex)
{
    throw;
}

The slight nuance that many people may not know is that if you just use "throw", the exception's stack trace is maintained.  But if you use "throw ex", the stack trace will start from that method where you threw the exception.  Most people that don't really know this end up using "throw ex", and I've always advocated the use of "throw".

Enter SqlExceptions.  When you log a SqlException, you will see at a minimum the following stack trace:

System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)

   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)

   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)

   at System.Data.SqlClient.SqlDataReader.ConsumeMetaData()

   at System.Data.SqlClient.SqlDataReader.get_MetaData()

   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)

   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)

   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)

   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)

   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)

   at System.Data.SqlClient.SqlCommand.ExecuteReader()

When trying to look at logs to investigate a crash, this is a lot of text for your eyes to parse through.  In this case, I find it better to catch the SqlException and rethrow it using this syntax:

try
{
    command.ExecuteNonQuery();
}
catch(SqlException ex)
{
    throw ex;
}

That way, you don't get the ridiculously long stack trace from within the sql command that you don't care about :-)

See more in the archives