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.
The Try BlockWhen 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.
The Catch BlockAfter 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.
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 BlockThe 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 StatementThe 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.
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
|