Directives

Writing an Exception Handler by Using Try...Catch...Finally

Exception handlers allow you to determine how an exception is treated, rather than rely on Visual Basic's default behavior, which is to display the exception and terminate the application. As I mentioned earlier, Visual Basic .NET supports structured exception handling in the form of a Try...Catch...Finally structure. This structure has the following syntax see Table 10-2 for a description of each component.

Try     ' Statements to try. Catch [exception  As  type] [When  expression]    ' Statements to run when an exception is thrown. Finally     ' Statements to run when execution leaves any other block in the     ' structure, such as Try or Catch. These statements run regardless    ' of whether an exception occurred. End Try 

 

Table 10-2. Components of the Try...Catch Finally Structure

Part

Description

Try

The Try section is where you place code that might cause an exception (i.e., all code other than exception-handling code). You can place all of a procedure's code within the Try section or just a few lines.

Catch

Code within the Catch section executes only when an exception occurs. This is where you place code to deal with an exception.

Finally

Code within the Finally section occurs when the code within the Try section and/or code within the Catch section completes. This section is where you place your "cleanup" code code that you want always executed regardless of whether an exception occurs.

 

Consider the following code:

Try    Debug.WriteLine("Try") Catch    Debug.WriteLine("Catch") Finally    Debug.WriteLine("Finally") End Try Debug.WriteLine("Done Trying") 

If you were to run this code, here's what would happen:

  1. The Try block would begin, and code within the Try section would execute.

  2. The code contains no errors, so no exception would be thrown. Therefore, the code within the Catch section wouldn't execute.

  3. When all statements within the Try section finished executing, the code within the Finally section would execute.

  4. When all statements within the Finally section finished executing, execution would jump to the statement immediately following End Try statement.

The following would print to the Output window:

Try Finally Done Trying 

Now consider this code:

Dim intNumerator As Integer = 10 Dim intDenominator As Integer = 0 Dim intResult As Integer Try    Debug.WriteLine("Try")    intResult = intNumerator / intDenominator Catch    Debug.WriteLine("Catch") Finally    Debug.WriteLine("Finally") End Try Debug.WriteLine("Done Trying") 

If you were to run this code, the following would be printed to the Output window:

Try Catch Finally Done Trying 

Notice that this time the code within the Catch section would execute. This happens because the statement that sets intResult causes an Overflow exception. Had this statement not been placed in within a Try block, Visual Basic would have raised the exception and an error dialog box would have appeared. However, because the statement is placed within the Try block, the exception would be "caught." This means that when the exception occurs, Visual Basic directs execution to the Catch section. Notice also how the code within the Finally section executes after the code within the Catch section. Remember, code within the Finally section always executes, regardless of whether an exception occurs.

Catching Exceptions

The Catch section is where you deal with an exception. Technically, you don't have to include a Catch section, but leaving it out is a very bad idea! Ignoring an exception (by not including a Catch section) is worse than not including exception trapping to begin with because exceptions will occur and neither you nor your customers will know about them.

Important

You should always include a Catch section to deal with exceptions.


 

Dealing with Exceptions

Catching exceptions so that they don't crash your application is a noble thing to do, but it's only part of the exception-handling process. Usually, you'll want to tell the user (in a friendly way) that an exception has occurred. Not only do you want to tell them an exception occurred, but you'll probably also want to tell them what type of exception occurred. To do this, you have to have a way of knowing what exception was thrown. This is also important if you intend to write code to deal with specific exceptions. The Catch statement allows you to specify a variable to hold a reference to an Exception object. Using this Exception object, you can get information about the exception. Here's the syntax used to place the exception in an Exception object:

Catch  variablename  As Exception 

If an exception occurs, you can manipulate the properties of the variable see Table 10-1 as you see fit. For instance, to simply inform the user of an error, you could use code such as this:

Try     ' Try something here. Catch ex As Exception    MessageBox.Show("Error: " & ex.Message, "Error!", _                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation) End Try 

Recall from Table 10-1 that the Message property of the Exception object contains the text that describes the specific exception that occurs. As with other code structures, Visual Basic has a statement that can be used to exit a Try...End Try structure at any time: Exit Try. Note, however, that if you use Exit Try, the Finally block will execute. When writing clean-up code in a Finally block for an exception handler that uses Exit Try, be sure that no problems arise from the Exit Try diverting code to the Finally block.

Handling a Specific Anticipated Exception

There may be times that you'll anticipate a specific exception being thrown. For example, you might write code that attempts to open a file when the file might not exist. In such an instance, you'll probably want to perform specific actions when the anticipated exception is thrown. When you anticipate a specific exception, you can create a Catch section designed specifically to deal with that one exception.

In the previous section, I showed how you could catch an exception using a Catch statement such as Catch e As Exception. By creating a generic Exception variable, such a Catch statement would catch any and all exceptions thrown by statements within the Try section. To catch a specific exception, change the data type of the exception variable to a specific exception type. For example:

Dim lngAnswer As Long Try    lngAnswer = 100 / CLng(txtInput.Text)    MessageBox.Show("100/" & txtInput.Text & " is " & lngAnswer)  Catch objException As System.OverflowException    MessageBox.Show("You must enter something in the text box.") Catch objException As Exception    MessageBox.Show("Caught an exception that wasn't an overflow.") End Try 

Notice that there are two Catch statements in this structure. The first Catch statement is designed to catch only an Overflow exception it won't catch exceptions of any other type. The second Catch statement doesn't care what type of exception is thrown. Catch sections are evaluated from top to bottom, much like Case statements in Select Case structure. This means the general Catch section shown here would never catch an Overflow exception.

You could add as many Catch sections as you need to catch other specific exceptions. However, if you are anticipating specific exceptions, it might be best to wrap that code in its own Try End Try structure, like this:

Try     ' Do stuff here.    ' The following code might generate an anticipated error     Try        ' Code that might generate an anticipated error.     Catch ex As AnticipatedError       ' Code to deal with anticipated error.     Catch        ' Code to deal with an unexpected error.     End Try Catch     ' Code to deal with an unexpected error. End Try 

Important

When specifying multiple Catch blocks for an exception handler, order them from most specific to least specific. This ensures that exceptions are handled correctly.


 

Exception Handlers and the Call Stack

It's extremely important to understand how exceptions are passed up the call stack. Although Try Catch Finally structures can be nested even across procedures, as shown in the following code only one Try block is active at any given point in time. Consider the following two procedures:

Private Sub cmdCreateErrorHandler_Click(ByVal sender As _                System.Object, ByVal As System.EventArgs) _                Handles cmdCreateErrorHandler.Click    ' Purpose   :  Create an error handler.     Try       Call TestSub()    Catch       MessageBox.Show("Error caught in Click event.")    End Try End Sub Private Sub TestSub()    ' Purpose   :  Demonstrate error handlers and the call stack.     Dim intNumerator As Integer = 100    Dim intDenominator As Integer = 0    Try        ' This next statement throws an exception.        Dim intResult As Integer = intNumerator / intDenominator    Catch       Messagebox.Show("Error caught in TestSub().")    End Try End Sub 

When the cmdCreateErrorHandler button is clicked, the Try statement creates an exception handler. When the TestSub method is invoked, its exception handler becomes enabled when its Try statement is encountered; any exceptions encountered within the Try structure in the TestSub method (such as the divide-by-zero error deliberately created here) are handled by the current exception handler. When the Try End Try structure is completed, the Try structure of the Click event becomes active once more.

Next consider these two procedures:

Private Sub cmdCreateErrorHandler_Click(ByVal sender As _                System.Object, ByVal As System.EventArgs) _                Handles cmdCreateErrorHandler.Click    ' Purpose   :  Create an error handler.     Try       Call TestSub()    Catch       MessageBox.Show("Error caught in Click event.")    End Try End Sub Private Sub TestSub()    ' Purpose   :  Demonstrate error handlers and the call stack.     Dim intNumerator As Integer = 100    Dim intDenominator As Integer = 0    ' This next statement throws an exception.     Dim intResult As Integer = intNumerator / intDenominator End Sub 

When the button is clicked, the Try statement creates an active exception handler. When the TestSub method is invoked, code is still executing within the Try structure of the Click event. When the exception occurs, Visual Basic looks back through the thread of execution to determine whether the code is executing within a Try block. In this case, it would determine that the code was indeed within a Try block, so the exception would be handled in the Click event, as illustrated by the following two procedures:

Private Sub cmdCreateErrorHandler_Click(ByVal sender As _                System.Object, ByVal As System.EventArgs) _                Handles cmdCreateErrorHandler.Click    ' Purpose   :  Create an error handler.     Try       Call TestSub()       MessageBox.Show("Statement in Click event.")    Catch       MessageBox.Show("An exception has been caught!")    End Try End Sub Private Sub TestSub()    ' Purpose   :  Demonstrate error handlers and the call stack.     Dim intNumerator As Integer = 100    Dim intDenominator As Integer = 0    ' This next statement throws an exception.     Dim intResult As Integer = intNumerator / intDenominator    MessageBox.Show("Statement in TestSub() method.") End Sub 

When the Click event is fired, an exception handler is enabled by the Try statement. When execution transfers to the TestSub procedure, the exception handler remains enabled because no Catch, Finally, or End Try statement has been reached. When the exception occurs, what's printed? Because the exception isn't part of a Try block within the same procedure, Visual Basic looks deeper in the call stack to see whether execution is occurring within a Try block higher up the stack. Because the code is within a Try block higher up the call stack, the exception is handled and the following text gets printed:

An exception has been caught! 

This concept is true for multiple nested procedures as well. If an exception occurs within a procedure and the code isn't contained in a Try block, Visual Basic looks up the call stack to see whether execution is occurring in a Try block somewhere deeper in the stack. If the top of the call stack is reached and code execution is found not to be running within a Try block, the exception is treated as untrapped (and rightly so). Such an error will cause a message to be displayed to the user, and your application will crash to the desktop.

Note

If an exception is encountered in a Catch block, one of two things happened. If an exception handler is wrapped around the current exception handler (or one higher up the call stack), the Finally block of the current exception handler is called, and execution then jumps to the Catch block of the next active exception handler. If no other exception handler is active, the program will crash.



Practical Standards for Microsoft Visual Basic. NET
Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 0735613567
EAN: 2147483647
Year: 2005
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net