Problem: Limited Error Handling Capabilities   
                                    
The error handling syntax of VB 6.0 is one of the more maligned VB constructs. The built-in Err object has
limited functionality. There is no way to extend the Err object with new functionality – through inheritance for
example. There is no support for automatic context gathering (line numbers, call stack, etc.). The On Error
command uses the verboten Goto statement.

VB  provides structured error handling through the now common (in other languages)
Try/Catch/Finally
keywords. The .NET runtime provides a very useful Exception object that provides a call stack trace.
Furthermore, you can create your own powerful custom exception classes by deriving from Exception and
extending its functionality. You can still use the On Error Goto syntax, but you cannot mix it with Try/Catch in
the same procedure.

Understanding Structured Exception Handling      
                         
VB  provides structured exception handling using
Try, Catch, Finally and Throw keywords. All .NET
exceptions derive from a common type:
System.Exception. This class provides a wealth of functionality.
Furthermore, you can create more powerful custom exception classes by deriving from Exception and extending
its functionality.

The System.Exception type defines numerous properties which are common to all exception types. Using these
properties you can obtain the error message, call stack, the name of any external help system, source of the
error, etc. Be aware that the Data property is only found in .NET 2.0 or higher. This property allows you to
pack in custom information to a new Exception object.




















Here is a simple example using Try/Catch/Finally. Note that:
      •        You can have multiple catch blocks designed to catch specific types of exceptions.
      •        The runtime executes the first catch block that matches the exception type. No others are executed.
      •        The finally block will always run before execution leaves the try block, even if another exception is
               thrown from within a catch.

Public Sub SomeMethod()
  Try
   ' Code which may raise an exception
    File.OpenText("SomeFileWhichIsNotHere.txt")

  Catch ex As FileNotFoundException
    Console.WriteLine("*** Error! ***")
    Console.WriteLine("Stack: {0}", ex.StackTrace)
    ' Rethrows the exception up the stack
    Throw ex

  Catch ex As Exception
    ' Catches all other exceptions from try scope
    Console.WriteLine("*** Caught a Exception ***")
    Console.WriteLine("Stack: {0}", ex.StackTrace)

  Finally
    ' This code will always execute just before exiting the try block
    Console.WriteLine("*** In the Finally Block ***")
  End Try
End Sub


Building Custom Exceptions          
                                                     
In a majority of cases, you will make use of Try/Catch/Finally to handle runtime errors which are thrown by
types in the .NET base class libraries. The .NET SDK documentation will show you wish exceptions can be
thrown by a given method of a given type.

When you are building your .NET programs, you may wish to create a ‘custom exception’ class. This can be
helpful with you want a strongly-typed error object, which is named in accordance to your problem-domain (e.
g., CustomerInvoiceException, MissingEmailException, etc). To build a strongly typed exception create a new
class which derives from System.Exception.

If you wish to follow Microsoft best-practices, all custom exceptions should:
      •        Have an Exception suffix on the class name.
      •        Be marked as serializable using the <Serializable> attribute.
      •        Define a constructor which allows the Message property to be set.
      •        Define a constructor which accounts for any ‘inner exceptions’.
      •        Defines a constructor which allows the object to be passed across remoting boundaries.

Here is an example of a custom exception (named CarIsDeadException) following these best-practices. This
example makes use of several new keywords (MyBase, Protected) and .NET programming constructs
(attributes). Don’t concern yourself with the syntactic details just yet. As you will see in your next lab, Visual
Studio provides a ‘code snippet’ which will auto-generate all of the necessary code.

' This exception represents a critical error that could
' be sent from a Car object (see next page).
<Serializable()> _
Public Class CarIsDeadException
 Inherits ApplicationException
  ' Core-constructors.
  Public Sub New()
  End Sub
  Public Sub New(ByVal message As String)
    MyBase.New(message)
  End Sub

  ' For inner exceptions.
  Public Sub New(ByVal message As String, ByVal inner As System.Exception)
    MyBase.New(message, inner)
  End Sub

  ' For remoting infrastructure.
  Protected Sub New(ByVal info As _
    System.Runtime.Serialization.SerializationInfo, _
    ByVal context As System.Runtime.Serialization.StreamingContext)
    MyBase.New(info, context)
  End Sub
End Class


Once you have defined a new custom exception class, you can throw it back to the caller using the Throw
keyword. Because custom exceptions are indeed classes, you must use the New keyword to create the object.

Here is a class named Car, which could thrown a CarIsDeadException when executing the Accelerate() method.
Once we have created the CarIsDeadException object, we are setting the Message property indirectly using the
custom constructor. The HelpLink property can be set to specify an external help file. As well, the Data
property provides access to an internal dictionary, and represents custom name / value pairs. Finally, assume
carIsDead is a Boolean member of the class, which marks if the car is functional or broken.

Public Class Car

  ' This field marks the ‘state’ of the Car.
  Private carIsDead As Boolean

  Public Sub Accelerate(ByVal delta As Integer)

    ' Is the Car currently working?  If not, throw our exception!
    If carIsDead Then

      ' Create a CarIsDeadException and set Message / HelpLink.
      Dim ex As CarIsDeadException = _
        New CarIsDeadException("Your car has exploded!")
      ex.HelpLink = "http://www.CarsRUs.com"

      ' Fill Data dictionary with two name/value pairs.
      ex.Data.Add("TimeStamp", _
        String.Format("The car exploded at {0}", DateTime.Now))
      ex.Data.Add("Cause", "You have a lead foot.")

      Throw ex
    End If

    ' If we get here, Car is working fine, assume other code
    ' executes.
    ...
  End Sub
End Class


When calling the Accelerate() method, we must wrap the call within Try/Catch logic. Notice that we are now
catching a CarIsDeadException object. As well, we are checking the Data property against Nothing.  If the value
is not Nothing, we know we have data we can process. We can iterate over the Data items using the internal
DictionaryEntry object.

Try

  Dim myCar As New Car()
  myCar.Accelerate(40)

Catch e As CarIsDeadException
  ' By default, the data field is empty, so check for Nothing.
  Console.WriteLine("-> Custom Data:" & vbLf)
  If e.Data IsNot Nothing Then
    For Each de As DictionaryEntry in e.Data
      Console.WriteLine("-> {0}: {1}", de.Key, de.Value)
    Next
  End If
End Try
Copyright (c) 2008.  Intertech, Inc. All Rights Reserved.  This information is to be used exclusively as an
online learning aid.  Any attempts to copy, reproduce, or use for training is strictly prohibited.
Exceptions
Table of Contents
Courseware
Training Resources
Tutorials
Services