Although you've been a Visual Basic 6.0 developer for years, and you've already used On Error statements in your Visual Basic 2005 code, you want to try out the structured error-handling statements you've heard so much about.
Use the TRy…Catch…Finally block statement to locally monitor and handle errors. The statement has three sections:
Here's the syntax of the TRy…Catch…Finally statement:
Try ' ----- Error-prone code here. Catch ex As System.Exception ' ----- Error-processing code here. Multiple ' Catch blocks can be included. Finally ' ----- Cleanup code here (optional). End Try
Although Visual Basic 2005 still supports the On Error statement and related error-handling logic found way back in Visual Basic 1.0, it also includes a new "structured" error-handling system that more closely parallels the object-oriented nature of .NET. In this system, exceptions (errors) exist as objects, inherited from the System.Exception class. When an error occurs in your code, .NET wraps it up in a System.Exception object (or one of its more specific derived classes) and triggers it in your code. The try…Catch statement watches for any such exceptions and jumps to a Catch block when an exception occurs.
System.Exception represents the most general type of exception; because all exception objects derive from it, it catches all error types. In this statement:
Try ' ----- Error-prone code here. Catch ex As System.Exception ' ----- Error-processing code here. End Try
any type of error that occurs in the try block, no matter what it is, falls into the Catch block, since that block catches every type of error.
.NET also defines more specific exceptions. For example, the System.OutOfMemoryException error occurs when any operation lacks sufficient memory to execute properly:
Try ' ----- Error-prone code here. Catch ex As System.OutOfMemoryException ' ----- Handle memory errors here. Catch ex As System.Exception ' ----- Handle all other errors here. End Try
Each Catch block handles only the error types specified in its As clause. In the above block of code, the first Catch block handles OutOfMemoryException errors. Any other error that occurs in the try block skips over that first Catch entry and jumps into the second, more general Catch block. This is what is meant by a "matching" Catch block, as mentioned earlier in this recipe. Exceptions seek the first matching Catch clause, based on an exact class match or a derived match relationship.
When an error occurs, the generated exception is compared to each Catch block's As clause for a match, in order from top to bottom. Therefore, you should place the most restrictive error type first, saving System.Exception for the last Catch block. If no error occurs, all Catch blocks are ignored.
Within a Catch block, the ex variable (included just after the Catch keyword) provides access to the actual exception object. Use its members as you would the members of any other object. A description of the exception appears as ex.Message. You can name the variable anything you want; the name ex has become common in technical documentation, but you are free to change it or even vary it between the different Catch clauses.
If included, the Finally block is always processed, no matter what. It is processed after the relevant TRy and Catch blocks complete. Even if you issue an Exit Sub or similar statement from within a try or Catch block, the Finally section is still processed. All TRy statements must include at least one Catch or Finally block.
There are some restrictions on TRy…Catch statements. In general, you cannot use GoTo statements to jump into or out of any of the blocks. There is an Exit Try statement that lets you jump out early, but it can't be used in the Finally block.
If an error occurs in a routine but no error handling is in effect (i.e., the code is out-side of a try statement, and no On Error statements appear in the procedure), the error "bubbles up" to the calling procedure, looking for another active error handler to deal with the exception. If no error handlers are available to deal with the error, a message is displayed to the user, and the application exits.
Recipe 15.3 discusses a global exception handler that Catches any exceptions not dealt with in local procedures.