Exception Fun and Games

Test your understanding of Try-Catch-Finally.

Troubleshooting Tricks

LANGUAGES: VB .NET

ASP.NET VERSIONS: 1.0 | 1.1

 

Exception Fun and Games

Test your understanding of Try-Catch-Finally.

 

By Don Kiely

 

Structured exception handling in .NET is new to many programmers. Other languages have had something similar for centuries, but now you can take advantage of it in any .NET language. Structured exception handling lets you write code based on assumptions and write it as though you know that it will never violate those assumptions. That's the code you put in a try block. Then you write catch blocks when those assumptions are violated. The benefit of this approach is that you don't have to litter your code with On Error statements in VB or complex conditional tests in any language.

 

That's Exception Handling 101. So consider this question, which is one variation of something asked frequently on online forums (the code is obviously VB .NET, but the idea applies to C# as well):

 

Sub Main()

  Try

    Try

      Throw New Exception("Original exception in try block")

    Finally

      Throw New Exception("Exception in finally block")

    End Try

  Catch ex As Exception

    Console.WriteLine(ex.Message)

  End Try

 

  Console.ReadLine()

End Sub

 

Before running the code, have some fun and test your knowledge. Answer these two questions:

 

1. What will be the message displayed in the console window?

 

2. Why? Make a strong case.

 

OK, this isn't too hard if you've delved into exceptions much. The first answer is that the message will be "Exception in finally block". Why? Here's what happens. The first line of executable code is to throw a new root exception object with the statement "Original exception in try block." That's an exception and because it is wrapped in a try block, the appropriate catch block executes. Because there is none here (make sure you understand that the applicable try block doesn't have one), the finally block executes. But that code throws a new exception, the one about being in the finally block.

 

That's the last thing that happens in that try block, so the Common Language Runtime (CLR) raises the exception to the next level. Most often, the CLR moves up the call stack to the procedure that called this one. If the code that caused this procedure to run is in a try block, the process is repeated to handle the exception. It there isn't a try block there, it continues up the call stack until it finds one or the default exception-handling mechanism kicks in. More Exceptions 101.

 

Now consider this: What happened to the first exception, the one calling itself the original exception? Where is it? How do you get access to it? Well, the way this code is written, it is gone forever to the great bit-bucket in the sky as soon as the code in the finally block executes. Under normal circumstances, you can only have a single exception object making its way up the call stack. So the finally block exception ends the life of the original exception.

 

One recent poster on a forum considers this behavior to be a bug in .NET, that the compiler (really the CLR) should force your code to deal with the original exception. The poster felt that allowing me to write code like this was something that .NET should protect me from. And it isn't a language issue, because the person used a C# example.

 

I responded by saying that this is by design, with good reason. If the CLR did as the poster wanted, you would have fat exception objects passing all over the place in your code or perhaps refusing to compile when it detected this kind of situation. .NET gives you the tools to be flexible with exceptions but imposing this through the compiler or CLR would take away that control.

 

Any time you catch an exception, you can do with it what you want. The several options include:

 

  • You can throw an entirely different exception - as is done in the previous code.
  • You can do something in response to the exception - such as log it or attempt to rectify the problem - and then re-throw the same exception object.
  • You can do something in response to the exception and then throw nothing, which causes execution to continue with any finally block and then with the next statement after the End Try statement.
  • You can simply ignore the exception - usually by using a catch statement with no exception specified and no code in the catch block.

 

And, with all the flexibility of structured exception handling in .NET, there are plenty of other options and variations on these themes.

 

You also can do what the poster seemed to want by including the original exception within a new exception. The code would look something like this:

 

Sub Main()

  Try

    Try

      Throw New Exception("Original exception in try block")

    Catch e As Exception

      Dim ex As New Exception("Exception in finally block", e)

      Throw ex

    End Try

  Catch ex As Exception

    Console.WriteLine(ex.Message)

    Console.WriteLine(ex.InnerException.Message)

  End Try

 

  Console.ReadLine()

End Sub

 

Notice that because you need a reference to the original exception you must add that exception in a catch block. The second parameter of the Exception object's constructor lets you pass in an exception object. You can't write to the InnerException property, so you have to do this in the constructor. Now the console displays this:

 

Exception in finally block

Original exception in try block

 

Make sure you understand why you get these results.

 

Structured exception handling in .NET is powerful, but with power comes responsibility. Put your power to good use, not evil!

 

Incidentally, this is the sort of topic that we discuss all the time in the various forums at http://www.asp.net, an online community sponsored by the ASP.NET team at Microsoft and moderated by independent developers like me. Pay us a visit; you'll find a lot of great help and support!

 

Don Kiely is senior technology consultant for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].

 

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish