Lesson 4: Handling and Throwing Exceptions

Lesson 4: Handling and Throwing Exceptions

After you have completed testing and debugging your application, run-time errors still might occur. For example, an application that saves data to a floppy disk will encounter an error if it attempts to save to a disk that is not ready. Even though the application code might execute as designed, an error still results. Visual Basic .NET and Visual C# provide structured exception handling as a means of writing code that recovers gracefully from errors and allows program execution to continue. You also can create and throw exceptions that communicate to the main program that an error has occurred.

After this lesson, you will be able to

  • Describe how exceptions are handled by the common language runtime

  • Create a structured exception handler

  • Throw exceptions from your code

Estimated lesson time: 30 minutes

How Exceptions Are Handled

When an application encounters a run-time error, it raises an exception. Exceptions are instances of specialized classes that derive from the base class System.Exception. Exceptions include features that facilitate diagnosis and management of the error, such as:

  • The Message property, which can contain a human-readable description of the error, as well as any other relevant information about the error.

  • The StackTrace property, which contains a stack Trace to allow tracing and pinpointing of where the error occurred in the code.

In addition to system-defined exceptions, you can create custom exceptions by extending System.ApplicationException. This is discussed in detail later in this lesson.

When a run-time error is encountered, an instance of the exception corresponding to the error is created and passed from the method that generated the error up the call stack to the method that called it. If an exception-handling structure is encountered in that method, it is handled there. If no exception-handling structure is found, the exception is passed up the call stack to the next method, and so on. If no exception-handling structure is found anywhere in the call stack, the default exception handler is engaged. The default handler causes a message box to display the type of exception and any additional information the exception provides, and then the application terminates, with no opportunity to save work or attempt to recover from the error.

With structured exception handling, you can provide a means for your application to recover from unexpected errors or at least to have the chance to save data before closing.

Creating an Exception Handler

Exception handlers are implemented for specific methods. Thus, each method you create can have its own exception handler, specifically tailored to the method and exceptions it is likely to throw. Methods that are likely to throw exceptions, such as methods that involve file access, should implement exception handling. Exception handlers use a Try Catch Finally syntax. The following three general steps are involved in creating an exception handler:

  1. Wrap the code with which the handler will be associated in a Try (try) block.

  2. Add one or more Catch (catch) blocks to handle the possible exceptions.

  3. Add any code that always must be executed to a Finally (finally) block. Such code will execute regardless of whether or not an exception is thrown.

The first step in creating an exception handler is to wrap the code in a Try (try) block. The Try (try) block forms the exception handler if any statement in the code throws an exception or if any unhandled exception is received through call stack bubbling, the method will attempt to handle it within this exception handler. If the exception cannot be handled, it will bubble farther up the call stack. The following example demonstrates the Try (try) block:

Visual Basic .NET

Try ' Normal program code goes here ' Error handling code, such as Catch and Finally blocks, goes here. ' The End Try statement encloses all error-handling code End Try

Visual C#

try { // Normal program code goes here } // Error handling code, such as catch and finally blocks, goes // here, outside of the curly braces that delimit the try block.

In Visual Basic .NET, you can exit a Try block by using the Exit Try statement.

A Try (try) block can be followed by one or more Catch (catch) blocks. A Catch (catch) block contains code to be executed when an exception is handled. Catch (catch) blocks can be generic, catching all possible exceptions, or specific, catching exceptions of a given class. The following example demonstrates a generic Catch (catch) block that will catch all exceptions thrown within a given Try (try) block:

Visual Basic .NET

' A Try block goes here Catch ' The Catch block is terminated by the End Try statement, ' another Catch block, or the Finally block. This code will execute ' if any run-time error is encountered during execution.

Visual C#

// A try block goes here catch { // The catch block is bounded by the curly braces. This code will // execute if any run-time error is encountered during execution. }

You also can obtain a reference to the exception that was thrown in the Catch (catch) statement. This can be useful because it allows you to access information contained within the exception in your error-handling routine. It also allows you to screen errors by type and create multiple Catch (catch) blocks to handle specific errors. The following example demonstrates how to catch a specific exception:

Visual Basic .NET

' A Try block goes here Catch e As System.NullReferenceException ' If a NullReferenceException is thrown, it will be caught in this ' block. The variable e contains a reference to the exception that ' you can use to examine the information contained therein. Catch e As System.Exception ' Since all exceptions derive from System.Exception, this block ' will catch any other exceptions that are thrown.

Visual C#

// A try block goes here catch (System.NullReferenceException e) { // If a NullReferenceException is thrown, it will be caught in // this block. The variable e contains a reference to the // exception that you can use to examine the information contained // therein. } catch (System.Exception e) { // Since all exceptions derive from System.Exception, this block // will catch any other exceptions that are thrown. }

Finally (finally) blocks contain code that must be executed regardless of whether an exception is thrown. This could be code to save data or release resources, or other code that is crucial to the application. The following code example demonstrates a Try Catch Finally (try catch finally) block:

Visual Basic .NET

Public Sub Parse(ByVal aString As String) Try Dim aDouble As Double ' If aString = Nothing, an ArgumentNullException will be thrown aDouble = Double.Parse(aString) Catch e As System.ArgumentNullException ' In this block, you would place any code that should be ' executed if a System.ArgumentNullException is thrown. Catch e As System.Exception ' This block will catch any other exceptions that might be ' thrown. Finally ' Any code that must be executed goes here. This code will be ' executed whether an exception is thrown or not. End Try End Sub

Visual C#

public void Parse(string aString) { try { double aDouble; aDouble = Double.Parse(aString); } catch (System.ArgumentNullException e) { // In this block, you would place any code that should be // executed if a System.ArgumentNullException is thrown. } catch (System.Exception e) { // This block will catch any other exceptions that might be // thrown. } finally { // Any code that must be executed goes here. This code will be // executed whether an exception is thrown or not. } }

If an error is encountered within a Try (try) block, execution is immediately transferred to the Catch (catch) blocks. The Catch (catch) blocks are then examined for one that can catch the exception. In the preceding example, there are two Catch (catch) blocks one that specifically catches an ArgumentNullException and one that catches any other exceptions. Only one Catch (catch) block will be executed per error. After the code in the Catch (catch) block has executed, the code in the Finally (finally) block is executed. Normal application execution then resumes at the next line after the line that called the error-containing routine.

NOTE
Because only one Catch (catch) block is executed per exception, you must write Catch (catch) blocks from the most specific to the least specific. Thus, place any Catch (catch) blocks for specific exceptions first in your code, and follow them with a generalized error-handling routine.

At times, you might not want to handle exceptions in the local routine but instead will bubble them up to the method that called your routine. Even so, you might have code that needs to run even in the event of an exception. In this case, you can omit the Catch (catch) block and use a Try Finally (try finally) structure as follows:

Visual Basic .NET

Try ' Method code goes here Finally ' Cleanup code goes here End Try

Visual C#

try { // Method code goes here } finally { // Cleanup code goes here }

To create an exception handler

  1. Wrap the code for which you want errors to be handled within a Try (try) block.

  2. If you want to handle exceptions locally, create one or more Catch (catch) blocks with the appropriate code to handle the exception.

  3. If you have code that must be executed even in the event of an exception, enclose it within the Finally (finally) block.

Throwing Exceptions

There might be times when you want to throw exceptions. Generally speaking, these occasions are divided into the following two situations:

  • You cannot completely handle a run-time error, but you want to partially handle it, and then bubble the exception up the call stack.

  • An unacceptable condition occurs in a component that cannot be handled locally and needs to be communicated to its parent. This might involve throwing either a standard .NET exception or a custom exception specific to your component.

In this section, we will examine these two situations in more detail.

Rethrowing Exceptions

At times, your exception-handling structure might be unable to fully handle an exception. For example, you might have a method that is performing an extensive series of complex calculations when suddenly a NullReferenceException is thrown. The method might or might not be able to handle the exception. Your code should test conditions and determine whether or not it can handle the exception. If the exception cannot be handled in the context of the Catch (catch) block, your code should rethrow the exception by using the Throw (throw) keyword. For example:

Visual Basic .NET

Try ' Insert code to be executed Catch e As System.NullReferenceException ' Code here should test the exceptions and current conditions to ' determine if the exception can be handled by the structure or if it ' bubbled up the stack. If it cannot be handled locally, the next line ' throws the exception further up the stack. Throw e End Try

Visual C#

try { // Insert code to be executed } catch (System.NullReferenceException e) { // Code here should test the exceptions and current conditions to // determine if the exception can be handled by the structure or if it // bubbled up the stack. If it cannot be handled locally, the next // line throws the exception further up the stack. throw e; }

If you have a generic Catch (catch) block that doesn t provide a reference to the exception, you can still rethrow the exception it receives by using the Throw (throw) keyword without any arguments. For example:

Visual Basic .NET

' This line is the beginning of a Catch block Catch Throw

Visual C#

// This line is the beginning of a catch block catch { throw; }

Alternatively, you might want to provide additional information to the next application level. Instead of rethrowing the same exception, you can wrap it in a new exception. The InnerException property is set in the constructor of a new exception and can hold a reference to an existing exception. Thus, you can supplement the information contained within the system exception by setting the relevant properties of a new exception and wrapping the original exception in the InnerException property. The following example demonstrates how to create and throw a new exception that provides an informative string message and wraps the original exception:

Visual Basic .NET

' This is the first line of a Catch block Catch e as NullReferenceException Throw New NullReferenceException("Widget A is not set", e)

Visual C#

// This is the first line of a catch block catch (NullReferenceException e) { throw new NullReferenceException("Widget A is not set", e); }

To rethrow an exception

Choose the appropriate option from the following:

  • Use the Throw (throw) keyword to throw the exception that was received by the Catch (catch) block.

  • Wrap the exception in a new exception that provides additional information and use the Throw (throw) keyword to throw it.

Custom Exceptions

A second scenario in which you might throw a new exception is in component development. If a condition occurs in your component that cannot be resolved, it is proper to throw an exception to the client application. Exceptions of this type are usually custom exceptions, because the common language runtime throws an exception if any of the standard exception conditions occur.

NOTE
Exceptions are for exceptional circumstances. They should not be used for client component communication you should use events for that. Exceptions should only be thrown when conditions make it impossible for program execution to proceed without intervention.

You can create custom exceptions by inheriting from the System.ApplicationException class. The ApplicationException class encapsulates all the functionality that an exception requires, including the Message, StackTrace, and InnerException properties, and can serve as a base for custom functionality tailored to your component. The following example demonstrates how to create a custom exception by inheriting from ApplicationException. This new exception requires a fictitious object named Widget in the constructor and exposes that object through a read-only property.

Visual Basic .NET

Public Class WidgetException Inherits System.ApplicationException ' This variable holds the Widget Private mWidget As Widget ' This property exposes the Widget Public ReadOnly Property ErrorWidget() As Widget Get Return mWidget End Get End Property ' The constructor takes a Widget, and a String that can be used ' to describe program conditions at the time of the error. You can ' provide different overloads of the constructor to take different ' sets of parameters Public Sub New(ByVal W As Widget, ByVal Message As String) ' Calls the constructor of the base class, and sets the Message ' property inherited from ApplicationException MyBase.New(Message) ' sets the Widget property mWidget = W End Sub End Class

Visual C#

public class WidgetException:System.ApplicationException { // This variable holds the Widget Widget mWidget; public Widget ErrorWidget { get { return mWidget; } } // The constructor takes a Widget, and a string that can be used // to describe program conditions at the time of the error. You can // provide different overloads of the constructor to take different // sets of parameters // // Declares the constructor for the class and calls the base class // constructor that sets the Message property inherited from // ApplicationException public WidgetException(Widget W, string S) : base(S) { // Sets the Widget property mWidget = W; } }

After you create your exception class, you can throw a new instance of it when conditions become unacceptable. For example:

Visual Basic .NET

Dim Alpha As New Widget() ' Code that corrupts Widget Alpha omitted Throw New WidgetException(Alpha, "Widget Alpha is corrupt!")

Visual C#

Widget Alpha = new Widget(); // Code that corrupts Widget Alpha omitted throw new WidgetException(Alpha, "Widget Alpha is corrupt!");

To throw a custom exception

  1. Define the custom exception class. It should inherit System.ApplicationException and expose any properties containing additional information for the clients that will handle the exception. The values of these properties should be assignable through the class s constructor.

  2. When appropriate, use the Throw (throw) keyword to throw a new instance of the exception, setting any appropriate parameters in the constructor.

Lesson Summary

  • Exceptions are how the common language run-time reports run-time errors. When an exception is thrown, it is passed up the call stack until it finds an exception-handling structure. If no such structure is found, an unhandled exception is handled by the runtime s default exception handler, which leads to program termination.

  • You can design routines to handle exceptions. These routines allow an application to recover from an unexpected error, or at least terminate gracefully. An exception-handling structure can consist of up to three parts:

    • Try (try) block

    • Catch (catch) block

    • Finally (finally) block

  • After an exception is handled, control returns to the method in which the exception-handling routine resides.

  • You can use the Throw (throw) keyword inside a Catch (catch) block to rethrow the exception currently being handled. This passes the exception up the call stack. You also can wrap the current exception in a new exception by setting the new exception s InnerException property.

  • You can create and throw custom exceptions by inheriting from the System.ApplicationException class. Exceptions should not be used for communication between components and clients; rather, they should be reserved for exceptional circumstances.



MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[.  .. ]0-316
MCAD(s)MCSD Self-Paced Training Kit(c) Developing Windows-Based Applications With Microsoft Visual Basic. Net a[. .. ]0-316
ISBN: 735619263
EAN: N/A
Year: 2003
Pages: 110

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