Exceptions The Visual Basic .NET Language

93 Violet = 64 End Enum Note two important things in this definition: • The first line of the definition starts with Flags . This indicates that values of this type can be composed of multiple items from the enumeration. • The items in the enumeration have values that are powers of two. This ensures that each combination of items has a unique sum. For example, the combination of Yellow, Blue, and Violet has a sum of 84, which cant be attained with any other combination of items. Individual values are combined using the Or operator. The ToString method is smart enough to sort out the value names when creating a string representation of the value. For example, given the previous assignment, consider the following call to the ToString method: Console.WriteLinemyRainbow.ToString This statement produces the following output: Green, Blue

2.18 Exceptions

Sometimes errors or exceptional conditions prohibit a program from continuing its current activity. A classic example is division by zero: Dim x As Integer = 0 Dim y As Integer = 1 \ x When the process hits the line containing the integer division, an exception occurs. An exception is any occurrence that is not considered part of normal, expected program flow. The runtime detects, or catches, this exception and takes appropriate action, generally resulting in termination of the offending program. Figur e 2- 3 shows the message box that is displayed when this code is run within the Visual Studio .NET IDE. Figure 2-3. A divide-by-zero exception Visual Basic .NET programs can and should be written to catch exceptions themselves. This is done by wrapping potentially dangerous code in Try...End Try blocks. Ex am ple 2- 9 shows how to catch the divide-by-zero exception. Example 2-9. Catching an exception Try Dim x As Integer = 0 Dim y As Integer = 1 \ x 94 Catch e As Exception Console.WriteLinee.Message End Try When the program attempts the division by zero, an exception occurs, and program execution jumps to the first statement in the Catch block. The Catch statement declares a variable of type Exception that receives information about the exception that occurred. This information can then be used within the Catch block to record or report the exception, or to take corrective action. The previous code merely displays the message associated with the exception that occurred, as shown here: Attempted to divide by zero. After executing the statements in the Catch block, program execution continues with whatever follows the End Try statement. In Try blocks in which no exception occurs, execution continues through to the last statement of the Try block and then skips the statements in the Catch block. The variable declared in the Catch statement of Ex am ple 2- 9 is of type Exception defined in the System namespace. All exceptions are represented by types that derive, either directly or indirectly, from the Exception type. The As type_name clause of the Catch statement specifies the type of exception that the associated block of code can handle. Exceptions of the indicated type, or of any type derived directly or indirectly from the indicated type, are handled by the associated block of code. Look again at the Catch statement from Ex am ple 2- 9 : Catch e As Exception Because all exceptions derive from the Exception type, any exception that occurs during execution of the Try block in Ex am ple 2- 9 results in execution of the Catch block. This behavior can be modified by providing a more specific exception type in the Catch statement. Ex am ple 2- 10 is identical to Ex am ple 2- 9 , except that it catches only divide by zero exceptions. Example 2-10. Catching a specific exception Try Dim x As Integer = 0 Dim y As Integer = 1 \ x Catch e As System.DivideByZeroException Console.WriteLinee.Message End Try If any exception other than DivideByZeroException were to occur in the Try block of Ex am ple 2- 10 , it would not be caught by the code shown. What happens in that case depends on the rest of the code in the program. Try...End Try blocks can be nested, so if there is a surrounding Try...End Try block with a suitable Catch statement, it will catch the exception. Alternatively, if the calling routine couches the method call within a Try...End Try block having a suitable Catch statement, execution jumps out of the current method and into the associated Catch block in the calling routine. If no suitable Catch block exists in the calling routine, the search for a suitable Catch continues up the call chain until one is found or until all callers have been examined. If no suitable Catch block exists anywhere in the call chain, the runtime environment catches the exception and terminates the application. Try...End Try blocks can include multiple Catch blocks, which allows different exceptions to be handled in different ways. For example, the following code handles two specific exceptions, allowing all others to go unhandled: Try 95 ... Catch e As System.DivideByZeroException ... Catch e As System.OverflowException ... End Try Because all exception types are derived from the Exception type, the properties and methods of the Exception type are available on all exception types. In fact, most exception types dont define any additional properties or methods. The only reason theyre defined as specific types is so that they can be specifically caught. The properties of the Exception class are: HelpLink A URN or URL that links to a help-file topic that explains the error in further detail. The type is String. HResult A COM HRESULT representing the exception. This is used for interoperating with COM components a topic that is not discussed in this book. The type is integer. InnerException Sometimes a method may choose to throw an exception because it has caught an exception from some other internal method call. The outer method throws an exception that is meaningful to it and its caller, but the exception thrown by the inner method should also be communicated to the caller. This is the purpose of the InnerException property. This property contains a reference to the internal exception if any that led to the current exception. The type is Exception. Message The message associated with the exception. In general, this is a description of the condition that led to the exception and, where possible, an explanation of how to correct it. The type is String. Source The name of the application or object in which the exception occurred. The type is String. StackTrace A textual representation of the program call stack at the moment the exception occurred. The type is String. TargetSite A reference to an object of type MethodBase defined in the System.Reflection namespace that represents the method in which the exception occurred. If the system cannot obtain this information, this property contains Nothing . The methods of the Exception class are: GetBaseException 96 As discussed for the InnerException property, indicates that the current exception may be the end exception in a chain of exceptions. The GetBaseException method returns the first exception in the chain. This method takes no parameters. The return type is Exception. GetObjectData Serializes the Exception object into a SerializationInfo object a process not discussed in this book. The syntax is: Overridable Public Sub GetObjectData _ ByVal info As SerializationInfo, _ ByVal context As StreamingContext _ Implements ISerializable.GetObjectData ToString Returns a text representation of the Exception. This includes the exception type, the message, the stack trace, and similar information for any inner exceptions. When an exception occurs, there is no facility for retrying the statement that caused the exception. If such behavior is desired, it must be explicitly coded. Heres one possibility: Dim bSuccess As Boolean = False Do Try Some code that is to be protected. ... bSuccess = True Catch e As Exception Some recovery action. ... End Try Loop Until bSuccess Sometimes you must ensure that certain code is executed regardless of whether there is an exception. For example, if a file is opened, the file should be closed even when an exception occurs. Try...End Try blocks can include Finally blocks for this purpose. Code appearing in a Finally block is executed regardless of whether an exception occurs. If no exception occurs, the statements in the Finally block are executed after the statements in the Try block have been executed. If an exception does occur, the statements in the Finally block are executed after the statements in the Catch block that handles the exception are executed. If the exception is not handled, or if there are no Catch blocks, the statements in the Finally block are executed prior to forwarding the exception to any enclosing exception handlers. Heres an example of using a Finally block: Dim s As System.IO.Stream =_ System.IO.File.Openc:\test.txt, System.IO.FileMode.CreateNew Try Do something with the open stream. ... Catch e As Exception Handle any exceptions. ... Finally The stream should be closed whether or not there is an error. s.Close End Try Visual Basic .NET applications can intentionally throw exceptions to indicate errors or other unusual occurrences. For example, if a method is expecting an argument that is within a specific range and the 97 actual value passed to the method is outside of that range, the method can throw an exception of type ArgumentOutOfRangeException defined in the System namespace. This is done with the Throw statement, as shown in Ex am ple 2- 11 . Example 2-11. Throwing an exception Public Sub SomeMethodByVal MyParameter As Integer Ensure that the argument is valid. If MyParameter 10 Or MyParameter 100 Then Throw New ArgumentOutOfRangeException End If Remainder of method. ... End Sub The Throw statement requires an instance of some type derived from the Exception type. When the Throw statement is reached, the runtime looks for an appropriate Catch block in the calling code to handle the exception. If no suitable Catch block is found, the runtime catches the exception itself and terminates the application. See Appendix B for a list of exception types defined in the System namespace. Visual Basic .NET applications can create their own exception types simply by declaring types that derive from the Exception type. Ex am ple 2- 12 shows how the exception handling of Ex am ple 2- 11 can be made more specific to the actual error that occurs. In Ex am ple 2- 12 , a new exception type called MyParameterOutOfRangeException is declared. Next, a method is shown that throws this exception. Lastly, a method is shown that handles the exception. Example 2-12. Defining and using a custom exception Define a custom exception class to represent a specific error condition. Public Class MyParameterOutOfRangeException Inherits Exception Public Sub New The Exception type has a constructor that takes an error message as its argument. Because the Message property of the Exception type is read-only, using this constructor is the only way that the Message property can be set. MyBase.NewThe value passed in the MyParameter parameter _ is out of range. The value must be in the range of _ 10 through 100. End Sub End Class ... Define a method that may throw a custom exception. Public Sub SomeMethodByVal MyParameter As Integer Ensure that the argument is valid. If MyParameter 10 Or MyParameter 100 Then Throw New MyParameterOutOfRangeException End If Remainder of method. ... End Sub ... Call the SomeMethod method, catching only the MyParameterOutOfRangeException exception. Public Sub SomeCaller 98 Try SomeMethod500 Catch e As MyParameterOutOfRangeException ... End Try End Sub What About On Error? Visual Basic 6 did not have exception objects and Try...Catch blocks. Instead, it used the On Error statement to specify a line within the current procedure to which execution should jump if an error occurred. The code at that point in the procedure could then examine the Err intrinsic object to determine the error that had occurred. For compatibility with previous versions, Visual Basic .NET continues to support the On Error and related statements, but they should not be used in new development, for the following reasons: • Structured exception handling is more flexible. • Structured exception handling does not use error codes. Application- defined error codes often clashed with error codes defined by other applications. • Structured exception handling exists at the .NET Framework level, meaning that regardless of the language in which each component is written, exceptions can be thrown and caught across component boundaries. Error handling with the On Error and related statements are not discussed in this book.

2.19 Delegates