Structured Exception Handling Overview for Visual Basic
Updated: July 2008
Visual Basic supports structured exception handling, which you can use to create and maintain programs with robust, comprehensive error handlers. Structured exception handling is code designed to detect and respond to errors during execution by combining a control structure (similar to Select Case or While) with exceptions, protected blocks of code, and filters.
Using the Try...Catch...Finally statement, you can protect blocks of code that have the potential to raise errors. You can nest exception handlers, and the variables declared in each block will have local scope.
For a related video demonstration, see How Do I: Email Unhandled Exceptions?.
The following code shows the structure of a Try...Catch...Finally statement.
Try ' Starts a structured exception handler. ' Place executable statements that may generate ' an exception in this block. Catch '[optional filters] ' This code runs if the statements listed in ' the Try block fail and the filter on the Catch statement is true. '[Additional Catch blocks] Finally ' This code always runs immediately before ' the Try statement exits. End Try ' Ends a structured exception handler.
The Try block of a Try...Catch...Finally exception handler contains the section of code to be monitored for exceptions. If an error occurs during execution of this section, Visual Basic examines each Catch statement within the Try...Catch...Finally until it finds one with a condition that matches that error. If one is found, control transfers to the first line of code in the Catch block. If no matching Catch statement is found, the search proceeds to the Catch statements of the outer Try...Catch...Finally block that contains the block in which the exception occurred. This process continues through the entire stack until a matching Catch block is found in the current procedure. If no match is found, an error is produced.
The code in the Finally section always executes last, just before the error-handling block loses scope, regardless of whether the code in the Catch blocks has executed. Place cleanup code, such as that for closing files and releasing objects, in the Finally section. If you do not need to catch exceptions, but do need to clean up resources, consider using the Using statement rather than a Finally section. For more information, see Using Statement (Visual Basic).
Catch blocks allow three options for specific error filtering. In one, errors are filtered based on the class of the exception (in this case ClassLoadException), as shown in the following code.
Try ' "Try" block. Catch e as ClassLoadException ' "Catch" block. Finally ' "Finally" block. End Try
If a ClassLoadException error occurs, the code within the specified Catch block is executed.
In the second error-filtering option, the Catch section can filter on any conditional expression. One common use of this type of Catch filter is to test for specific error numbers, as shown in the following code.
Try ' "Try" block. Catch When ErrNum = 5 'Type mismatch. ' "Catch" block. Finally ' "Finally" block. End Try
When Visual Basic finds the matching error handler, it executes the code within that handler, and then passes control to the Finally block.
When trying to find a Catch block to handle an exception, each block's handler is evaluated until a match is found. Since these handlers can be calls to functions, there may be unexpected side effects; for example, such a call can change a public variable that is then used in the code of a different Catch block that ends up handling the exception.
As a third alternative, you can combine options one and two, using both for exception handling. Your Catch statements should move from most specific to least specific. A Catch block by itself will catch all exceptions derived from Exception, and therefore should always be the last block before Finally.
The following example shows another simple error handler that uses the Try...Catch...Finally statement.
Option Strict On Imports System.IO Module Module1 Private Const FileName As String = "TestFile.data" Public Sub Main() ' First, create a new data file and write some data to the file. ' 1. Create the new, empty data file. If File.Exists(FileName) Then File.Delete(FileName) End If Dim fs As New FileStream(FileName, FileMode.CreateNew) ' 2. Create a BinaryWriter object for the data. Dim writer As New BinaryWriter(fs) ' 3. Write some sample data to the file. For i = 0 To 10 writer.Write(i) Next i writer.Close() fs.Close() ' Now read from the file you just made. ' 1. Create a BinaryReader object for the data stream. fs = New FileStream(FileName, FileMode.Open, FileAccess.Read) Dim reader As New BinaryReader(fs) ' 2. Read data from TestFile.data. The loop terminates with an ' EndOfStreamException when an attempt is made to read past ' the end of the stream. Try ' This loop terminates with an EndOfStreamException when it ' reaches the end of the stream. While True Console.WriteLine(reader.ReadInt32()) End While Console.WriteLine("The data was read with no error.") ' 3. Report the first error that is caught, if there is one. Catch eosExcep As EndOfStreamException ' This Catch block is executed when the reader attempts ' to read past the end of the stream. Console.WriteLine("End-of-stream exception occurred.") Catch IOExcep As System.IO.IOException ' For this Catch block, some other error occurred before ' the end of stream was reached. Print the standard ' exception message. Console.WriteLine(IOExcep.Message) Finally ' The Finally block is always executed. Console.WriteLine("Executing the Finally block.") reader.Close() fs.Close() End Try End Sub End Module
The Finally block is always run, regardless of any actions occurring in preceding Catch blocks. You cannot use Resume or Resume Next in structured exception handling.
In the preceding example, any exception other than the IOException class or the EndOfStreamException class is propagated back to the caller unhandled.