A V I S U A L B A S I C . N E T
C R A S H C O U R S E
Structured Exception Handling
One of the more complex and important aspects of application development iserror handling. Errors that are not handled can have devastating effects on thesuccess of any application because, in most cases, the application will not beable to recover or shut down gracefully. Among the challenges is the lack ofcomprehensive error handling across languages and platforms.To complicate matters further, handling errors is only t he tip of theproverbial iceberg. As important as error handling is, an application must beable to handle unacceptable application level events or exceptions that are notnecessarily system generated error. Now, the term “error handling” is nolonger sufficient.
Exception handling deals with any system or application generated error,what we now refer to as an exception. This ability to handle all exceptions, bothsystem and application generated, goes a long way toward giving the user a stableapplication and a better overall user experience.
The CLR is a language independent means for exception handling thatplaces all raised or thrown errors into an exception object that can be manipulatedlike any other object. In addition, the exception object can be created andused, programmatically, anywhere within an application.
The CLR implements exception handling with the Try/Catch/Throwmodel. This model of exception handling, while foreign to Visual Basic programmers,is well known by C++ programmers. This is a structured exceptionhandling model that is time tested and proven as a solid means for handling ordealing with thrown exceptions.
Throwing an exception is similar to raising an error in Visual Basic. Thesimplest exception structure is as follows:
Public Sub MySub()Try'Some codeCatch'Deals with any exception that may occur.End TryEnd Sub
In its most basic form, all application and exception code goes into what iscalled a Try block. In this example, the Try block is the area between the Tryand the End Try statements.
The Try block can be divided into three clauses. The area between the Tryand Catch statements is where you place your applications code. The areabetween the Catch and, in this case, the End Try statements are where yourexception handling code resides. Another section, defined as the finally clause,is available in the last clause where the Try blocks code executes. Our simpleexception handling example does not use the finally clause as it is not requiredwhen a Catch statement is available.
Exception Handling Rules
A set of rules governs how the Try block can be used. But before we have a lookat these rules, let’s take a quick look at some of the classes that support exceptionhandling.
Table 7-3 lists several common exception classes you can look forward tousing. Exception classes are thrown when a related exception is thrown; whenlooking for exceptions look for the following:
Table 7-3: Exception Classes
Exception Class Reason Exception Class Is Thrown
|System.AppDomainUnloadedException Thrown when attempting to use an unloadedapplication domain.
System.ApplicationException Thrown when a non-fatal application error hasoccurred.
System.ArgumentException Thrown when an argument passed is not valid.
System.ArgumentNullException Thrown when a null is passed as a method parameterthat does not accept null values.
System.ArgumentOutOfRangeException Thrown when a passed value is outside the range of amethods parameter.
System.ArithmeticException Thrown when an error occurs while performingarithmetic and conversion operations.
System.ArrayTypeMismatchException Thrown when adding a value of the incorrect data typeto an array.
System.DivideByZeroException Thrown whenever a value is divided by zero.
System.IndexOutOfRangeException Thrown when trying to access an invalid index in an array.
System.InvalidCaseException Thrown when an invalid conversion attempt is made.
System.NullReferenceException Thrown when attempting to dereference a null object reference.
System.OutOfMemoryException Thrown when memory is not available to perform the specified task.
System.OverflowException Thrown when an operation overflow occurs.
System.RankException Thrown when an array with the wrong number of dimensions is passed to a methods parameter.
System.SystemException Is the base class for all exception classes in the System namespace.
System.Data.ConstraintException Thrown when a constraint is violated.
System.Data.DataException Thrown when an ADO.NET component generates an error.
System.Data.DBConcurrencyException Thrown when the number of rows affected in an update procedure is zero.
System.Data. DeletedRowInaccessibleException Thrown when attempting to perform data manipulation operations on a data row that has been deleted.
System.Data. InvalidConstraintException Thrown when a data relationship is violated.
System.Data. NoNullAllowedException Thrown when inserting a null value where one is not accepted.
System.IO. DirectoryNotFoundException Thrown when a specified directory cannot be found.
System.IO.FileLoadException Thrown when a file cannot be loaded.
System.IO.IOException Thrown when an I/O error occurs.
System.IO.PathToLongException Thrown when a path or file name are too long.
System.Runtime.Remoting. Thrown when an error occurs during a remote RemotingException operation.
System.Runtime.Remoting. RemotingTimeoutException Thrown when the response of a server or client exceed a predefined interval.
System.Runtime.Remoting.ServerException Thrown when an error occurs while working with a remote component that is an unmanaged application incapable of throwing an exception.
System.Runtime.Serialization.SerializationException Thrown when an error occurs during the serialization or deserialization of a component.
System.Web.HttpException Allow an http exception to be thrown.
System.XML.XmlException Provides exception information about the last XML exception.
Basic rules govern the use of a Try block. (They will quickly become obvious after using Try blocks a few times.)
- All Try blocks must employ at least one catch or finally clause.
- A Catch clause with no other parameters will catch all unhandled exceptions.
- The finally clause always executes when available except when an Exit Tryoccurs. As such, the finally clause is a good place to perform componentcleanup. If an Exit Try statement is used anywhere in the Try block then itis better to perform cleanup after the End Try block statement.
- Developers familiar with the On Error statement may still perform errorhandling as they did in Visual Basic only when a Try block does not exist inthe procedure.
Exception Handling Examples
For the following examples we will create a single Windows Form and add a buttonfor each example. To begin, create a new project and name it “ExceptionHandler”.
One popular and easy way to understand an example of error handling hasalways been the divide by zero error, or in .NET terms “exception.” You will usethe divide by zero exception wherever possible so as to not distract you fromwhat the chapter is trying to convey. (You will examine a few other specificexception conditions later in this chapter.)
This example demonstrates the simplest of all exception structures:
1. Drag a button onto your Windows Form and label it “Try Catch”.
2. Change the buttons name to “btnTryCatch”.
3. Apply the following code in the click event of the button.
Dim intResult as Integer"Dim int1 as Integer = 5Dim int2 as Integer = 0Try intResult = int1 / int2Catch objException as System.OverflowException Messagebox.Show("Divide by zero has occurred")End Try
The preceding example evaluates the exception object by using the catchclause. The catch clause checks to see if the exception object contains an”OverflowException” exception. If so, and in this case it will, the code in thecatch clause executes.
The Finally Clause
This example employs the same code as the one previously, except it demonstratesthat the Finally clause always executes:
1. Drag another button onto your Windows Form and label it “Finally”.
2. Change the buttons name to “btnFinally”.
3. Apply the following code in the click event of the button.
Dim intResult as IntegerDim int1 as Integer = 5Dim int2 as Integer = 0Try intResult = int1 / int2Catch objException as System.OverflowException Messagebox.Show("Divide by zero exception has occurred")Finally Dim obj As New System.Text.StringBuilder() obj = obj.Append("Regardless of whether or not an ") obj = obj.Append("exception occurs, the Finally clause ") obj = obj.Append("will execute.") MessageBox.Show(obj.ToString) obj = NothingEnd Try
Feel free to remove the errant code with “intResult = int1 / 1” andobserve that the finally clause still executes.
The Exit Try Statement
This example demonstrates the Exit Try statement. You could simply add the Exit Try statement to a previous example: however, go ahead and create a new button to keep each example separate for future reference.
1. Drag another button onto your Windows Form and label it “Exit Try”.
2. Change the button name to “btnExitTry”.
3. Cut and paste code from the Finally button to the Exit Try button.
4. In the Catch clause, place the “Exit Try” statement after the messageboxstatement:
Dim intResult as IntegerDim int1 as Integer = 5Dim int2 as Integer = 0TryintResult = int1 / int2Catch objException as System.OverflowExceptionMessagebox.Show("Divide by zero exception has occurred")Exit TryFinallyDim obj As New System.Text.StringBuilder()obj = obj.Append("Regardless of whether or not an ")obj = obj.Append("exception occurs, the Finally clause ")obj = obj.Append("will execute.")MessageBox.Show(obj.ToString)obj = NothingEnd Try
You will notice when the exception occurs, the exceptions message is displayed and the Try block is exited. In this case, the Finally block does not execute and is not a good place to clean up objects in memory.
Multiple Catch Statements
It is often preferable to use Multiple Catch statements in a single Try block, although the placement of Catch statements can impact performance. Once an exception is caught, the processing of the remaining Catch statements is aborted. Subsequently, once the Catch clause completes processing, the Finally clause is processed if available. To increase the performance of your Try blocks, place the most likely one to error or more common exceptions in the first Catch blocks while placing the least likely errors toward the end. Here’s how to use Multiple Catch statements:
1. Drag another button onto your Windows Form and label it “Multiple Catch”.
2. Change the button name to “btnMultipleCatch”.
3. Cut and paste code from the Finally button to the Multiple Catch button.
4. Make the following changes as highlighted in the code below:
Dim intResult As IntegerDim int1 As Integer = 5Dim int2 As Integer = 0Dim str1 As StringTrystr1 = int1 / int2Throw (New Exception("A different exception"))Catch objException As System.OverflowExceptionMessageBox.Show("Divide by zero exception has occurred")CatchMessageBox.Show("Some other exception has occured.")FinallyDim obj As New System.Text.StringBuilder()obj = obj.Append("Regardless of whether or not an ")obj = obj.Append("exception occurs, the Finally clause ")obj = obj.Append("will execute.")MessageBox.Show(obj.ToString)obj = NothingEnd Try
As you step through the procedure you will notice that you no longerreceive an overflow exception. You will also notice that the string value receivingthe results of the calculation has the value “infinity” when dividing a number byzero. The overflow exception does not occur, however, when we threw an exceptionto the calling method. The first Catch clause is completely ignored, but thesecond Catch clause is not looking for any specific exception; as a result, the secondCatch clause catches all exceptions not already caught.
Historically, when you were building COM components, the best practice was to ensurethat all methods and components handled their own exceptions. The best practice with.NET components is to pass the exception to the client and allow the client to determinethe next course of action. This is due in part because all languages now understand howto deal with each other’s languages exceptions, therefore, it is no longer critical for thelanguage catching the exception to also deal with the exception. Also, exceptions don’talways correlate to an error that occurred. Often an exception simply indicates anapplication state that is not what the method requires. This could be as simple as thedatabase is not available. In this care, no error has occurred in the code; however,because the database is unavailable, the method cannot complete its assigned task.
Getting Exception Information
The exception class has several properties and methods. You’ll learn about a fewof the more notable ones here and then examine an example of each:
- Source property: The Source property of the exception class is intended to hold the application or object name generating the exception. It can also be programmatically set, but if it is not set, the property returns the assembly name where the exception occurred.
- Message property: The Message property is a string containing a description of the current exception.
- TargetSite property: The TargetSite property is a string containing the name of the procedure where the exception occurred.
- GetType method: The GetType method is inherited from the System.Object class and returns the type of exception that has occurred.
- ToString method: The ToString method returns a string describing the current exception including information provided by several other exception class properties and methods.
Exception Class Properties and Methods Example
This example demonstrates the use of some exception class properties and methods:
1. Drag another button onto your Windows Form and label it “Properites/Methods.”
2. Change the button name to “btnPropMeth.”
3. Cut and paste code from the Finally button to the Properties/Methods button.
4. Add the following code to the newly pasted code:
Dim intResult as IntegerDim int1 as Integer = 5Dim int2 as Integer = 0TryintResult = int1 / int2Catch objException as System.OverflowExceptionMessagebox.Show("Divide by zero exception has occurred")'Source, Message, TargetSite, GetType, ToStringMessageBox.Show("Source: " & objException.Source())MessageBox.Show("Message: " & objException.Message())MessageBox.Show("TargetSite: " & amp; objException.TargetSite.Name)MessageBox.Show("GetType.Name: " & amp; objException.GetType.Name)MessageBox.Show("ToString: " & amp; objException.ToString())FinallyDim obj As New System.Text.StringBuilder()obj = obj.Append("Regardless of whether or not an ")obj = obj.Append("exception occurs, the Finally clause ")obj = obj.Append("will execute.")MessageBox.Show(obj.ToString)obj = NothingEnd Try
This is the second of three parts of a sample chapter from The Book of Visual Studio .NET, ISBN 1-886411-69-7 from No Starch Press
# # #