Structured exception handling was introduced to Visual Basic programmers with the first .NET version of the language. Structured exception handling is important for two reasons:
- It simply makes code more readable by using a syntax that is more congruent with the rest of the language compared to the old On Error Goto... statement.
- It is much more powerful than the On Error Goto... statement and provides a greater level of flexibility and control.
Catching and Throwing Exceptions
Exception handling is implemented with the Try...Catch...Finally...End Try statement. The basic syntax looks like this:
Try ' Code that could raise an exception. Catch ' Code to handle the exception. Finally ' Code to cleanup (close database connections, etc.). End Try
The Try and End Try statements are both required. The Catch and Finally statements may both be used in a Try block, but at least one of them is required. Also, multiple Catch statements are allowed to handle different types of exceptions. If you have multiple Catch blocks, order them from the most specific type of exception to the least specific:
Try ' Code that could raise an exception. Catch ex As ArgumentOutOfRangeException ' Handle an invalid argument possibly using a default ' value so the code can continue Catch ex As Exception ' Handle any other type of exception Finally ' Code to cleanup (close database connections, etc.). End Try
You also can throw exceptions in your code. This is useful when you catch an exception in part of your code, perform some cleanup code, and then throw the exception so a higher-level procedure can catch it. Throwing exceptions is also useful when creating custom exception types.
To throw an exception, you would write something like this:
Throw New ArgumentOutOfRangeException
ArgumentOutOfRangeException tells the Throw statement what type of exception to throw. The ArgumentOutOfRangeException type is just one of the many that the .NET Framework provides.
When an exception occurs somewhere in your code, you can propagate it in three ways:
- Do nothing and let it propagate back up the call stack automatically.
- Catch it and re-throw it. This allows you to run some cleanup code in the Finally block.
- Catch it, wrap the exception in another exception using the InnerException property, and throw the new exception back to the calling procedure. The InnerException property lets you maintain the original exception and its information inside a more relevant exception.
Introducing Custom Exceptions
Although the .NET Framework provides many standard exceptions, you also can create, throw, and catch your own custom exceptions. In general, Microsoft recommends that you use the standard exceptions provided by the .NET Framework. However, if your application has a need that a standard exception does not satisfy, you can create a custom exception.
When you create a custom exception type, you gain control of all of the exceptions properties. You also can add properties to your custom exception class. This gives you a place to store crucial pieces of data besides embedding them in the Message property. This makes retrieval of the crucial data simple without parsing them out of the Message property.
Custom Exception Sample Application
To understand custom exceptions, create a very simple command line application. You can download all of the code and necessary files here and from the link at the end of the article.
The code package includes a very simple MS Access database that contains one table, named Customer. Not surprisingly, the Customer table contains a list of customers with ID, first name, last name, and address details. The actual contents of the database are not important, but data access is a good context for your custom exception.
For the application, I created a new console application in the VB 2005 Express IDE.
DatabaseException Base Class
If you're going to have more than one custom exception, it's a good idea to create a custom base class for them. This base class will inherit from the System.Exception class that the .NET Framework provides. It also will contain the three constructors that will be common to all of your custom exceptions. The sample application's base class is called DatabaseException; the code is listed below:
Public Class DatabaseException Inherits Exception Public Sub New() End Sub Public Sub New(ByVal message As String) MyBase.New(message) End Sub Public Sub New(ByVal message As String, ByVal inner As Exception) MyBase.New(message, inner) End Sub End Class
The three constructors are the standard constructors provided by the System.Exception class. The first allows you to create an exception without using any parameters, just the default exception properties. The second allows you to specify a message string to use as the Message property of your exception. Finally, the third constructor also allows you to specify the message string, but it lets you specify an exception as the second parameter as well. The System.Exception class has a property called InnerException that is useful when you catch an exception and want to wrap it inside a more relevant exception. By setting the InnerException property, you can maintain all of the information in the original exception.
One last note about the base class: There seems to be some disagreement as to whether you should inherit from the System.Exception class or the System.ApplicationExeption class. Most of the older literature from Microsoft states you should inherit from System.ApplicationException, but the new philosophy seems to state that you should instead inherit from the System.Exception class. I'm not sure what, if any, technical differences there are, but I tested with the base class inheriting from each and it works both ways. For the purposes of the sample application, follow the newer philosophy and inherit from System.Exception. Perhaps exploring this difference is fodder for a future article.