2

As far as I know, you are supposed to only use try/catch when you will actually handle the exception and not just report&log it and then crash the application. Otherwise, you are better off just checking different scenarios where it makes sense (e.g. if sth==null) or - if your purpose is just to log the exception and crash the application - to use AppDomain.UnhandledException. But is this always the case and why?

Suppose the following method, which accepts an array and returns MemoryStream after doing some database and filesystem operations.

MemoryStream Read (int[] IDs)
{
    try
    {
        using (SqlConnection connection = new SqlConnection(connection_string))
        {
            connection.Open();    

                        // a bunch of code executing SQL queries & constructing MemoryStream, which is returned at the end of the block
        }
    }
    catch (Exception e)
    {
        // report the exception to the user & log it
        throw; // pointles??                
    }
}

There are multiple situations that can be considered exceptional/unwanted behavior, such as:

  • argument (IDs[]) being null,
  • failure to establish an SQL connection,
  • failure to execute a specific SQL query.

All these cases are considered exceptional, still putting everything inside a try/catch if you only want to log an exception (then crash) is probably bad practice - but why? What would be the best handling behavior in the above case? Avoid try/catch completely, check null references using an if statement (return null in such case) and use AppDomain.UnhandledException to log everything else? Use try/catch, but still check for null references inside using if statements (and return in that case)? Something else?

w128
  • 4,680
  • 7
  • 42
  • 65
  • Even if you don't find my answer to be useful, I suggest you read the links I provided. I'm sure you'll find them invaluable! – alan Jan 31 '13 at 15:20
  • @alan, thank you for your answer, I do find it useful and am in the process of reading the links. =) – w128 Jan 31 '13 at 15:25

3 Answers3

2

Peppering your code with try/catch statements only to crash the app isn't productive. The CLR already takes care of that for you. And you've got AppDomain.UnhandledException to generate decent information to diagnose the cause.

Only in the very specific case that you have to clean up something, say a file that you don't want to keep laying about, should you consider writing a try/catch. Which in itself is a very iffy requirement, there is no guarantee whatsoever that your catch block will execute. It will not when the exception is nasty like StackOverflowException or ExecutionEngineException. Or the more common reason that programs don't clean up after themselves, somebody tripping over the power cord or killing the process from Task Manager.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • There are a number of reasons to catch an exception you're not planning on cleaning up after. One being to format the exception and return something that is user-friendly or to prevent sensitive stack trace information from being broadcast to the world. Also, in your catch block example you would not use a catch for the file clean up, use a finally block instead; it's always guaranteed to execute even after an exception. – alan Jan 31 '13 at 15:15
  • To be exact, from what I know, finally{} is actually not guaranteed to _always_ execute - for example, StackOverflowException or power failure will not result in its exectuion. – w128 Jan 31 '13 at 15:20
  • In the case of a standard exception (which is all you'll ever be expected to log/handle) it is guaranteed to execute. I think considering stack overflows or power failure might be a little bit excessive. – alan Jan 31 '13 at 15:25
1

you are supposed to only use try/catch when you will actually handle the exception and not just report & log it and then crash the application

I agree with the first part, although I would add that adding logging at the tier boundaries is valuable when you may not have control over the calling tier. e.g. I log all exceptions that occur in a Web Service at the top method to ensure I have logging on the server since debug info (stack trace, etc) does not always cross comm layers gracefully

In your particular example I would check for "exceptional" conditions where you can but let other exception occur "naturally". For your specific examples:

  • argument (IDs[]) being null,
  • failure to establish an SQL connection,
  • failure to execute a specific SQL query.

For the first one, I would check for null arguments for one reason: A NullReferenceException gives you no context about the cause of the exception, other that where it occurs. I much prefer to check for null and then throw a new ArgumentNullException exception since you can add which argument is null. You may still need to do some digging to find out why it's null but it saves you a lot of time in debugging.

SQL Exceptions can typically bubble up naturally, since they have decent error information in them (e.g. "undeclared variable '@arg'")

D Stanley
  • 149,601
  • 11
  • 178
  • 240
1

I've recently began reading up on this topic myself. My basic understanding is:

  1. Only catch an exception if you plan to handle it.
  2. Overuse of try/catch can lead to exception swallowing and/or the loss of valuable stack trace information and can lead to maintainability issues (what if you decide to standardize your errors/logging?). Instead use try/finally or using blocks to implement clean up.
  3. Catch exceptions at the boundaries via a global exception handler.
  4. Use AppDomain.UnhandledException for exactly what the name implies: logging unhandled exceptions. If you do not log these you'll only find a CLR "Windows Error Reporting" entry in the log viewer and a few dump files that are really of no use to you. It's always a good idea to utilize AppDomain.UnhandledException so if your application does crash you know why.

It's important to note that "handling" an exception doesn't necessarily mean clean up or retroactive logic. Handling could simply mean formatting an error to something more user-friendly or to hide a sensitive stack trace you wouldn't want just anyone to see. I routinely log a detailed error and return a formatted one.

Again, this is just what I've gathered initially. Below are some sources:

Good Exception Management Rules of Thumb

Understanding and Using Exceptions

alan
  • 6,705
  • 9
  • 40
  • 70
  • Great links, thanks. It seems that implementing a global exception handler is a good choice if you simply want to report and log the exceptions in a consistent way - a clean, sample implementation is provided here: [link](http://stackoverflow.com/questions/3133199/net-global-exception-handler-in-console-application) – w128 Jan 31 '13 at 15:48