Troubleshooting Tips and Tricks
LANGUAGES: C# | VB.NET
TECHNOLOGIES: Exception Handling
Supercharge Exception Handling
Get to know the ins and outs of Try-Catch-Finally.
By Don Kiely
VB .NET Exceptions
One of the Web pages in the sample code from my previous article, ResultHandling.aspx, contains a Try-Catch-Finally block that is probably a bit more complex than you're likely to put in most of your procedures, but it'll do for explanation. Figure 1 contains a portion of VB .NET's version of the Page Load event procedure, in which a few numbers are divided.
Dim x As Integer = 44
Dim y As Integer = 0
Dim z As Double
Dim zi As Double
z = x / y
zi = x \ y
lblResult.Text = "When x is " & x.ToString _
& " and y is " & y.ToString _
& ", x / y is " & z.ToString _
& ", and x \ y is " & zi.ToString & "."
Catch ex As DivideByZeroException When y.ToString = Nothing
Response.Write("The divisor is nothing.")
Catch ex As DivideByZeroException When y.ToString = ""
Response.Write("The divisor is an empty string.")
Catch ex As DivideByZeroException When y = 0
Response.Write("The divisor is zero.")
Catch ex As Exception
Dim sMessage As String
sMessage = "<font face='Comic Sans MS'>" _
& "<h4>" & Request.Url.ToString() & "</h4>" _
& "<pre>" & Server.GetLastError().ToString() _
Response.Write("<P><FONT face='Comic Sans MS'>" _
& "<A href='Default.aspx'>Return to Default.aspx" _
Figure 1. Here is part of VB .NET's Page Load event procedure. Because one is zero, the code throws a DivideByZeroException. This exception is defined by the .NET Framework.
The code included in each Catch statement is called an exception filter, consisting of the specific exception object and optional When clause. The filter's exception object must be System.Exception or derived from it. The contents of the When clause must evaluate to True or False and can reference the properties of the Catch block's exception object.
The first three Catch blocks catch a specific type of .NET exception, DivideByZeroException. But they also use the Catch statement's optional When clause to customize the response further for specific conditions surrounding the problem. Here, I check whether the divisor "y" is Nothing (in VB .NET), an empty String (which really can't happen with typed variables and Option Strict On), or equal to zero.
The last Catch block is a catch-all block of last resort. Because all exceptions are derived from System.Exception, any other exception that occurs when the code in the Try block runs is caught by the last Catch block.
The important concept here is the order of Catch blocks. The rule is to include Catch blocks for more specific exceptions first, followed by increasingly less specific exceptions, generally ending with a Catch block for System.Exception. This way you can get as specific as you need when handling problems.
The basic idea of exceptions and Try-Catch-Finally blocks is the same in C# as it is in VB .NET, but with just enough differences to trip up a programmer moving from one language to the other. Figure 2 shows the equivalent code from the C# version of the ResultHandling.aspx page.
int x = 44;
int y = 0;
z = (double)x / (double)y;
zi = x / y;
lblResult.Text = "When x is " + x.ToString()
+ " and y is " + y.ToString()
+ ", x / y is " + z.ToString()
+ ", and x \\ y (integral) is " + zi.ToString()
catch (DivideByZeroException ex)
Response.Write("The divisor is nothing.");
Response.Write("The divisor is an empty string.");
Response.Write("The divisor is zero.");
sMessage = "<font face='Comic Sans MS'>"
+ "<h4>" + Request.Url.ToString() + "</h4>"
+ "<pre>" + Server.GetLastError().ToString()
Response.Write("<P><FONT face='Comic Sans MS'>"
+ "<A href='Default.aspx'>Return to Default.aspx"
Figure 2. Here is the C# version of the ResultHandling.aspx page.
There are two big differences in this code. The first is there is no C# equivalent to VB .NET's When clause on the Catch statement, so you must resort to a switch block or some other construct to achieve the same result. The previous code catches the same DivideByZero exception, but then tests the value of variable y to see whether it is null, an empty string, or 0.
The order of the catch blocks also is important in C#, but if you have them in the wrong order in VB .NET, the code happily compiles and executes just fine. The C# compiler instead raises a compile-time error if you include a more general exception before one that is more specific. It uses the order of inheritance for the various exceptions to ensure you're not making a mistake with it.
Try-Catch-Finally provides a powerful way to handle exceptions in .NET applications. But there is far more than first meets the eye. Learning about its idiosyncrasies in your language of choice will go a long way toward robust code and applications.
Don Kiely is senior information architect for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].