Visual Basic 的结构化异常处理概述

Visual Basic 支持结构化异常处理,您可以使用该处理创建和维护具有可靠、全面的错误处理程序的程序。 结构化异常处理是旨在通过将控制结构(类似于 Select Case 或 While)与异常、受保护的代码块和筛选器结合起来,在执行期间检测和响应错误的代码。

使用 Try...Catch...Finally 语句,可以保护可能引发错误的代码块。 可以嵌套异常处理程序,并且在每个块内声明的变量将具有局部范围。

链接到视频 相关的视频演示,请参见如何 Do I 通过电子邮件发送未处理的异常吗?

Try...Catch...Finally 语句

以下代码显示了 Try...Catch...Finally 语句的结构。

Try
    ' Starts a structured exception handler.
    ' Place executable statements that may generate 
    ' an exception in this block.
Catch '[optional filters]
    ' This code runs if the statements listed in 
    ' the Try block fail and the filter on the Catch statement is true.
'[Additional Catch blocks]
Finally
    ' This code always runs immediately before
    ' the Try statement exits.
End Try
' Ends a structured exception handler.

Try...Catch...Finally 异常处理程序的 Try 块包含监视异常的代码段。 如果在执行此代码段时发生错误,则 Visual Basic 会检查 Try...Catch...Finally 中的每个 Catch 语句,直到找到条件与该错误匹配的语句。 如果找到这样的语句,则控制转移到 Catch 块中的第一个代码行。 如果没有找到匹配的 Catch 语句,则继续搜索包含发生异常的块的外部 Try...Catch...Finally 块的 Catch 语句。 此过程在整个堆栈中继续,直到在当前过程中找到匹配的 Catch 块。 如果找不到任何匹配,将产生错误。

Finally 段中的代码总是最后执行,并且刚好在超出错误处理块范围之前执行,不论 Catch 块内的代码是否已执行。 将清理代码(如用于关闭文件和释放对象的代码)放在 Finally 段中。 如果不需要捕捉异常,而确实需要清理资源,请考虑使用 Using 语句而不是 Finally 段。 有关更多信息,请参见 Using 语句 (Visual Basic)

Catch 块中的错误筛选

Catch 块允许三个用于特定错误筛选的选择。 其中一个基于异常的类(本例中为 ClassLoadException)筛选错误,如以下代码所示。

Try
    ' "Try" block.
Catch e as ClassLoadException
    ' "Catch" block.
Finally
    ' "Finally" block.
End Try

如果发生 ClassLoadException 错误,则执行指定的 Catch 块内的代码。

在第二个错误筛选选择中,Catch 段可基于任何条件表达式进行筛选。 这种类型的 Catch 筛选器的一个常见用途是测试特定的错误号,如以下代码所示。

Try
   ' "Try" block.
Catch When ErrNum = 5 'Type mismatch.
   ' "Catch" block.
Finally
   ' "Finally" block.
End Try

当 Visual Basic 找到匹配的错误处理程序后,会执行该处理程序内的代码,然后将控制传递到 Finally 块。

提示

当尝试找到一个 Catch 块来处理异常时,要计算每个块的处理程序直到找到匹配块。 由于这些处理程序可以是函数调用,因此这可能会导致意想不到的副作用;例如,这样的调用可能改变随后将在另一个最终处理异常的 Catch 块的代码中使用的公共变量。

第三种选择是将选择一和选择二结合起来,同时用于异常处理。 Catch 语句应从处理最特定的异常变为处理最一般的异常。 Catch 块本身会捕捉所有从 Exception 派生的异常,因此它应始终是 Finally 之前的最后一个块。

从 Try…Catch 块中分支

从 Catch 块中分支回最初的 Try 语句或 End Try 语句是可能的,但不可能分支到封闭的 Try…Catch 块中。 如下所示:

Try Catch 分支

结构化异常处理程序示例

下面的示例显示了另一个使用 Try...Catch...Finally 语句的简单错误处理程序。

Option Strict On
Imports System.IO

Module Module1
    Private Const FileName As String = "TestFile.data"

    Public Sub Main()

        ' First, create a new data file and write some data to the file.
        ' 1. Create the new, empty data file.
        If File.Exists(FileName) Then
            File.Delete(FileName)
        End If
        Dim fs As New FileStream(FileName, FileMode.CreateNew)

        ' 2. Create a BinaryWriter object for the data.
        Dim writer As New BinaryWriter(fs)

        ' 3. Write some sample data to the file.
        For i = 0 To 10
            writer.Write(i)
        Next i
        writer.Close()
        fs.Close()

        ' Now read from the file you just made.
        ' 1. Create a BinaryReader object for the data stream.
        fs = New FileStream(FileName, FileMode.Open, FileAccess.Read)
        Dim reader As New BinaryReader(fs)

        ' 2. Read data from TestFile.data. The loop terminates with an
        ' EndOfStreamException when an attempt is made to read past
        ' the end of the stream.
        Try
            ' This loop terminates with an EndOfStreamException when it 
            ' reaches the end of the stream.
            While True
                Console.WriteLine(reader.ReadInt32())
            End While
            Console.WriteLine("The data was read with no error.")
        ' 3. Report the first error that is caught, if there is one.
        Catch eosExcep As EndOfStreamException
            ' This Catch block is executed when the reader attempts
            ' to read past the end of the stream.
            Console.WriteLine("End-of-stream exception occurred.")
        Catch IOExcep As System.IO.IOException
            ' For this Catch block, some other error occurred before
            ' the end of stream was reached. Print the standard
            ' exception message.
            Console.WriteLine(IOExcep.Message)
        Finally
            ' The Finally block is always executed.
            Console.WriteLine("Executing the Finally block.")
            reader.Close()
            fs.Close()
        End Try
    End Sub

End Module

不论前面的 Finally 块中发生什么操作,Catch 块始终运行。 不能在结构化异常处理中使用 Resume 或 Resume Next

提示

在前面的示例中,IOException 类或 EndOfStreamException 类以外的任何其他异常都不经处理传播回调用方。

请参见

任务

异常处理疑难解答 (Visual Basic)

参考

Try...Catch...Finally 语句 (Visual Basic)

BinaryReader

BinaryWriter

FileStream

概念

异常处理介绍 (Visual Basic)

错误类型 (Visual Basic)

非结构化异常处理概述 (Visual Basic)

其他资源

异常处理任务 (Visual Basic)