Handling Exceptions

One of the most fundamental and often most complex tasks of a developer is to design exception-handling procedures in order to allow an application to recover gracefully from an unexpected or disallowed condition.

The .NET Framework allows exception handling to be performed between languages, across multiple computers, and even through integration with COM and other legacy solutions. Within Visual Basic .NET, the most common methods of exception handling involve the Try , Catch , and Finally blocks in addition to the Throw statement.

graphics/tip_icon.gif

The Try, Catch , and Finally blocks must be consecutive within code. You may not have intervening code separating these blocks when configuring event-handling solutions within your code. Everything between the Try and End Try keywords is part of a single error-handling unit.


The Try Block

When code is processed that may generate an exception, the code may be placed within a Try block, which must in turn be followed by one or more Catch blocks or a Finally block. Exceptions raised cause the CLR to search for the nearest Try block (which may be nested within one another) and then pass control to the following Catch block or on to the Finally block if no Catch block is present in the code.

A Try block in its most basic form looks like this:

 Try     ' Code that may cause an exception Catch     ' Code that handles any exception End Try 

Any normal code may be placed within the Try block, including another Try block or calls to methods including Try blocks of their own. When an exception occurs, the CLR will find the nearest Try block and pass control to the following associated exception-handling blocks.

graphics/alert_icon.gif

A Try block must be followed by one or more Catch blocks or by a Finally block.


The Catch Block

After an exception is encountered within a Try block, control is passed to the following Catch blocks or to the Finally block. Catch blocks are evaluated in order until a match to the exception type is made. A particular exception might be matched by many different Catch blocks of varying levels of generality.

For example, a DivideByZeroException might match a Catch block for DivideByZeroException , ArithmeticException , SystemException , or Exception . These are all increasingly general exception classes that contain the specific DivideByZeroException . If no matching Catch block can be found, the exception is passed back to the code that raised the exception and is considered an unhandled exception, which is discussed in greater detail later in this chapter.

graphics/note_icon.gif

The default behavior for an unhandled exception is to cause the program to terminate with an error message.


graphics/tip_icon.gif

Because Catch blocks are evaluated in the order that they occur in your code, you must always place the most specific exceptions first if you have multiple Catch blocks. Otherwise, the code will not compile.


A Try block followed by some Catch exception blocks might look like this:

 Private Sub btnCalculate_Click(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles btnCalculate.Click     Try         Dim decMiles As Decimal = Convert.ToDecimal(txtMiles.Text)         Dim decGallons As Decimal = Convert.ToDecimal(txtGallons.Text)         Dim decEfficiency As Decimal = decMiles / decGallons         txtEfficiency.Text = String.Format("{0:n}", decEfficiency)         ' each  try block should at least have one catch or finally block         ' catch blocks should be in order of specific to the generalized         ' exceptions. Otherwise compilation generates an error     Catch fe As FormatException         Dim msg As String = String.Format("Message: {0}" & _          vbcrlf & "Stack Trace: " & vbcrlf & " {1}", _          fe.Message, fe.StackTrace)         MessageBox.Show(msg, fe.GetType().ToString())     Catch dbze As DivideByZeroException         Dim msg As String = String.Format("Message: {0}" & _          vbcrlf & " Stack Trace: " & vbcrlf & " {1}", _          dbze.Message, dbze.StackTrace)         MessageBox.Show(msg, dbze.GetType().ToString())         ' catches all CLS-compliant exceptions     Catch ex As Exception         Dim msg As String = String.Format("Message: {0}" & _          vbcrlf & " Stack Trace: " & vbcrlf & " {1}", _          ex.Message, ex.StackTrace)         MessageBox.Show(msg, ex.GetType().ToString())         ' catches all other exceptions including         ' non-CLS-compliant exceptions     Catch         ' just rethrow the exception to the caller         Throw     End Try End Sub 

Here, an exception raised within the code is thrown to the Catch blocks in order to see if a match is made. The inclusion of the Catch block that uses the general Exception class will prevent an unhandled exception. When this code is compiled and run, an input zero value ( DivideByZeroException ), a nonnumeric value ( FormatException ), or a very large numeric value ( OverflowException , caught by the Catch block as an exception) will not cause the program to terminate. A message will be returned to the user and the application will continue to function.

All languages that follow the Common Language Specification (CLS) will generate an exception that derives from System.Exception . The final Catch block in the code example (which does not specify an exception type at all) is included to handle exceptions generated by possible nonCLS-compliant languages. An unspecified Catch block is the most general form of Catch possible and should always be the last Catch block if multiple Catch blocks are present, because the first matching Catch block will be the one performed.

The Finally Block

The Finally block includes code that will run regardless of whether an exception is raised. This is a good location for cleanup code that will close open files or disconnect database connections to release held resources.

The following is an example of code that includes a Finally block:

 Private Sub btnSave_Click(ByVal sender As System.Object, _  ByVal e As System.EventArgs) Handles btnSave.Click   ' A StreamWriter writes characters to a stream   Dim sw As StreamWriter   Try      sw = New StreamWriter(txtFilename.Text)      ' Attempt to write the textbox contents in a file      Dim strLine As String      For Each strLine In txtText.Lines          sw.WriteLine(strLine)      Next      ' This line only executes if there were no exceptions so far      MessageBox.Show("Contents written, without any exceptions")      ' Catches all CLS-compliant exceptions   Catch ex As Exception      Dim msg As String = String.Format( _       "Message: {0}" & vbcrlf & " Stack Trace: " & vbcrlf & _       " {1}", ex.Message, ex.StackTrace)      MessageBox.Show(msg, ex.GetType().ToString())      GoTo endit      ' The finally block is always executed to make sure that the      ' resources get closed whether or not an exception occurs.      ' Even if there is a goto statement in a catch or try block the      ' finally block is first executed before the control goes to the label   Finally      If Not sw Is Nothing Then          sw.Close()      End If      MessageBox.Show( _       "Finally block always executes whether or not exception occurs")   End Try EndIt:    MessageBox.Show("Control is at label: end") End Sub 

The Finally block may also be used in conjunction with a Try block, without any Catch blocks. Exceptions raised would be returned as unhandled exceptions in this case. An example of the simplest form of this follows :

 Try     ' Write code to allocate some resources Finally     ' Write code to Dispose all allocated resources End Try 

The Throw Statement

The Throw statement can be used to explicitly throw an exception within your code. It can be used in order to re-throw a caught exception to perform a task such as generating an Event Log entry or sending an email notification of the exception, or it may be used in order to raise a custom exception explicitly defined within your code.

graphics/note_icon.gif

Exceptions should only be handled or explicitly thrown when doing so improves application usability and robustness. Evaluation of exception-handling code adds to the resource requirements needed to run your application and can rapidly become "too much of a good thing."


Here's an example of a Throw statement in its simplest form being used to re-throw a caught exception:

 Catch ex As Exception     ' TODO: Add code to write to the Event Log     Throw 

To use the Throw statement with a custom error message, you may create something like this:

 Dim strMessage As String = "EndDate should be greater than the StartDate" Dim exNew As ArgumentOutOfRangeException = _  New ArgumentOutOfRangeException(strMessage) Throw exNew 
graphics/note_icon.gif

The .NET Framework CLR includes many standard exception types, but on occasion it is necessary or desirable to create a custom exception to address a specific need within your code. This should be done only if there is not already an existing exception class that satisfies your requirements. Any new custom exception should use the System.ApplicationException class as its base class.




Developing and Implementing WindowsR-based Applications with Visual BasicR. NET and Visual StudioR. NET Exam CramT 2 (Exam 70-306)
Developing and Implementing WindowsR-based Applications with Visual BasicR. NET and Visual StudioR. NET Exam CramT 2 (Exam 70-306)
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 188

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