Exceptions in .NET–part I

After a great month of vacations, it’s time to go back to work.

And this time, I’ll write a couple of posts about exceptions and exception handing in .NET. In .NET, we should generate an exception when a member (method or property) fails to complete its task correctly. Did you noticed the “fails to complete its task correctly” part? It might be a little bit cryptic, so let’s expand it a little more. Say you’ve got a method which needs to change the value of an integer field as a result of some operation performed over another object it receives as a parameter. There might be some assumptions here…for instance, suppose that that method needs the passed in object to be in a specific state…if that doesn’t happen, then you probably should signal that by generating (ie, throwing) an exception. If you’re consuming that method, then you need to know how to handle an exception. And that is what I’ll discuss in this post.

Let’s take a look at an example…the following snippet illustrates how we can handle exceptions in our code:

private void DoSomething() {
    //some code
    //now enter region where we may get
    //an exception
    try {
                
    }
    catch(InvalidCastException ex) {
        //handle an invalid cast exception1
    }
    catch(AmbiguousMatchException ex) {
        //handle an invalid cast exception
    }
    catch(Exception ex) {
        //catch any exception
        //could also ommit the Exception variable
        //but using it lets us log the exception
        //after logging it, you should probably let it flow
        throw;
    }
    finally {
        //clean up everything here
    }
    //code after exception handling block
}

Whenever you write code that might throw an exception, it’s a good idea to wrap it up with a try block and specify the exceptions you’re prepared to handle . As you can see, the DoSomething method can recover from the specifics InvalidCastException and AmbiguousMatchException exceptions (notice the use if the catch keyword). Within a catch block, you’ll probably find some logging code which gets and logs information about the current exception. If you’re not able to recover from the exception, then your best option is simply to rethrow the current exception (as it’s shown in the catch all exception block – the third catch instruction). Don’t be tempted to rethrow the exception by writing throw ex;. If you do that, you’ll end up with a new exception stack and the original error stack is lost!

Having said this, there are several choices you can make at the end of the catch block. You can:

  1. rethrow the exception (as shown in the global catch block in the previous snippet);
  2. create a new (richer) exception and throw it (notice that this is not the same as throw ex; I’ve mentioned before);
  3. simply let the thread “leave” the current catch block.

(We’ll return to this in a future post.)

As you probably know, the catch block code will only be executed when the code in the try block generates an exception. When you have several catch blocks (as in the previous example), the CLR will evaluate them from top to botton in the order they were declared until it finds one whose parenthetical expression’s (ie, the expression which appears after the catch keyword) catch type is compatible with the current exception’s type. That’s why you should always put the more specific exceptions at the top.

If the CLR doesn’t find any matching catch code block associated with the try block where the exception was thrown (this doesn’t happen in the previous example because there’s a catch all code block), then it will keep looking in the current call stack until it finds a matching catch block or until it reaches the top of the call stack. In this last case, you’ll end up with an unhandled exception (more about this in future posts). On the other hand, when the CLR finds a matching catch block, then it will go “back” and execute all the “inner” finally code blocks, starting from within the one associated with the try block that threw the exception and stopping in the catch block that is responsible for handling the current exception. At this point, the CLR executes the code of that catch code block and, only then, will it execute the associated finally block code (provided that you don’t rethrow the current exception or throw a new exception from within the last catch code block!).

Notice that the CLR guarantees that the code in the finally block is always executed (even when there’s no exception), making it the appropriate spot for putting your clean up code. I’d say that the typical example of this is opening a file stream and ensuring it gets closed:

private void OpenAndCloseFile() {
    FileStream str;
    try
{
        //open filestream here
        //might throw exception
    }
    catch(IOException ex) {
        //log it
        //just let go
    }
    finally {
        if(str!= null ) {
            str.Close(  );
        }
    }
}

The finally block is optional and it must always be defined after all catch blocks (if there are any). After finishing executing the instructions defined in a finally block, the thread will simply jump into the next instruction.

Before ending this post, there’s still time to mention that it’s possible that some code defined within catch or finally blocks might end up throwing an exception. This is definitely *not* a good thing, but it’s also not the end of the world. When this happens, the CLR’s exception handling mechanism I’ve explained in the previous paragraphs will kick in and execute again as if the exception was thrown after the finally block. Notice, however, that all the information about the original exception is completely lost (it’s as if it didn’t happen).

And I guess this is it for now. Stay tuned for more on exceptions.

Advertisements

~ by Luis Abreu on September 7, 2011.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: