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

提供了一种方法,用于处理给定代码块中可能发生的一些或所有可能的错误,同时仍在运行代码。

语法

Try
    [ tryStatements ]
    [ Exit Try ]
[ Catch [ exception [ As type ] ] [ When expression ]
    [ catchStatements ]
    [ Exit Try ] ]
[ Catch ... ]
[ Finally
    [ finallyStatements ] ]
End Try

组成部分

术语 定义
tryStatements 可选。 语句 (s) 可能出现错误。 可以是复合语句。
Catch 可选。 允许多个 Catch 块。 如果在处理块时出现异常 TryCatch 则将以文本顺序检查每个语句,以确定它是否处理异常,并 exception 表示已引发的异常。
exception 可选。 任何变量名称。 exception 的初始值是引发的错误的值。 与一起使用 Catch 以指定捕获的错误。 如果省略,则该 Catch 语句将捕获任何异常。
type 可选。 指定类筛选器的类型。 如果的值 exception 是由 type 或派生类型指定的类型,则该标识符将绑定到异常对象。
When 可选。 Catch带有子句的语句 When 仅在计算结果为时才捕获异常 expression TrueWhen子句仅在检查异常的类型后应用,并且 expression 可以引用表示异常的标识符。
expression 可选。 必须可隐式转换为 Boolean 。 描述泛型筛选器的任何表达式。 通常用于按错误号进行筛选。 与关键字一起使用 When ,以指定捕获错误的情况。
catchStatements 可选。 语句 (s) 来处理相关块中发生的错误 Try 。 可以是复合语句。
Exit Try 可选。 用于中断结构的关键字 Try...Catch...Finally 。 继续执行语句后面的代码 End TryFinally语句仍将被执行。 不允许在 Finally 块中使用。
Finally 可选。 Finally当执行离开语句的任何部分时,始终会执行块 Try...Catch
finallyStatements 可选。 语句 (s) ,在所有其他错误处理发生之后执行。
End Try 终止 Try...Catch...Finally 结构。

备注

如果预计在代码的特定部分中可能出现特定的异常,请将代码放在块中, Try 使用 Catch 块保留控件并处理异常(如果发生)。

Try…Catch语句由一个 Try 块后跟一个或多个 Catch 子句组成,这些子句指定不同异常的处理程序。 在块中引发异常时 Try ,Visual Basic 将查找 Catch 处理异常的语句。 如果找不到匹配的 Catch 语句,Visual Basic 将检查调用当前方法的方法,并在调用堆栈上向上进行。 如果未 Catch 找到任何块,则 Visual Basic 向用户显示未处理的异常消息,并停止执行程序。

您可以 Catch 在一个语句中使用多个语句 Try…Catch 。 如果这样做,子句的顺序很 Catch 重要,因为它们是按顺序进行检查的。 在使用更笼统的子句之前获取特定性更强的异常。

以下 Catch 语句条件是最不具体的条件,将捕获派生自类的所有异常 Exception 。 在 Catch Try...Catch...Finally 捕获所需的所有特定异常后,通常应将这些变体中的一个作为结构的最后一个块。 控制流永远不会到达 Catch 遵循这些变化之一的块。

  • typeException ,例如:Catch ex As Exception

  • 语句没有 exception 变量,例如: Catch

如果 Try…Catch…Finally 语句嵌套在另一个 Try 块中,Visual Basic 首先检查 Catch 最内层块中的每个语句 Try 。 如果未找到任何匹配 Catch 的语句,则搜索将继续对 Catch 外部块的语句执行 Try…Catch…Finally

块中的局部变量 Try 在块中不可用, Catch 因为它们是单独的块。 如果要在多个块中使用变量,请在结构外声明变量 Try...Catch...Finally

提示

Try…Catch…Finally语句作为 IntelliSense 代码段提供。 在 "代码片段管理器" 中,展开 " 代码模式"-如果为,则依次尝试 Catch、Property 等,然后 ) 处理 (异常。 有关详细信息,请参阅代码片段

Finally 块

如果有一个或多个必须在退出结构之前运行的语句 Try ,请使用 Finally 块。 控件在传递到 Finally 结构外之前传递到块 Try…Catch 。 即使结构内的任何位置发生异常,也是如此 Try

Finally块可用于运行任何必须执行的代码,即使存在异常也是如此。 Finally无论块退出的方式如何,都将控制传递到块 Try...Catch

Finally即使代码遇到 Return 或块中的语句,块中的代码也会 Try 运行 Catch 。 在以下情况下,控件不会从 TryCatch 块传递到相应的 Finally 块:

将执行显式传输到块中是无效的 FinallyFinally除了通过异常以外,将执行转移到块外是无效的。

如果 Try 语句不包含至少一个 Catch 块,则它必须包含一个 Finally 块。

提示

如果不必捕获特定的异常,则该语句的 Using 行为类似于 Try…Finally 块,并保证资源的处置,而不管退出块的方式如何。 即使出现未经处理的异常也是如此。 有关详细信息,请参阅 Using 语句

异常参数

Catchexception 参数是类的实例 Exception ,或者是从类派生的类 ExceptionException类实例对应于块中发生的错误 Try

对象的属性 Exception 可帮助确定异常的原因和位置。 例如,属性将 StackTrace 列出导致异常的被调用方法,从而帮助你查找代码中发生错误的位置。 Message 返回描述异常的消息。 HelpLink 返回指向关联帮助文件的链接。 InnerException 返回 Exception 导致当前异常的对象; 或者,如果没有原始异常,则返回该对象 Nothing Exception

使用 Try ... 时的注意事项Catch 语句

只使用 Try…Catch 语句来表明出现异常或意外的程序事件。 原因如下:

  • 在运行时捕获异常将产生额外的开销,并且可能比预检查更慢,以避免异常。

  • 如果 Catch 未正确处理某个块,则可能不会正确向用户报告该异常。

  • 异常处理使程序更复杂。

并非始终需要 Try…Catch 语句来检查可能出现的情况。 下面的示例检查文件是否存在,然后再尝试打开它。 这减少了捕获由方法引发的异常的需求 OpenText

Private Sub TextFileExample(ByVal filePath As String)

    ' Verify that the file exists.
    If System.IO.File.Exists(filePath) = False Then
        Console.Write("File Not Found: " & filePath)
    Else
        ' Open the text file and display its contents.
        Dim sr As System.IO.StreamReader =
            System.IO.File.OpenText(filePath)

        Console.Write(sr.ReadToEnd)

        sr.Close()
    End If
End Sub

确保块中的代码 Catch 可以正确地向用户报告异常,无论是通过线程安全日志记录还是适当的消息。 否则,例外可能仍然未知。

异步方法

如果用 Async 修饰符标记方法,可以在方法中使用 Await 运算符。 带有运算符的语句 Await 挂起了方法的执行,直到等待的任务完成。 任务表示正在进行的工作。 当与运算符关联的任务完成时 Await ,将在同一方法中继续执行。 有关详细信息,请参阅在 Async program 中控制 Flow

异步方法返回的任务可能会以错误状态结束,这表示它由于未处理的异常而完成。 任务还可以以 "已取消" 状态结束,导致 OperationCanceledException 从 await 表达式引发。 若要捕获任一类型的异常,请将 Await 与任务关联的表达式放置在 Try 块中,并在块中捕获该异常 Catch 。 本主题后面提供了一个示例。

任务可能处于错误状态,因为多个异常负责错误的发生。 例如,任务可能是对 Task.WhenAll 调用的结果。 当你等待此类任务时,捕获的异常只是异常之一,你无法预测将捕获的异常。 本主题后面提供了一个示例。

Await表达式不能位于 Catch 块或块中 Finally

迭代器

迭代器函数或 Get 访问器对集合执行自定义迭代。 迭代器使用 Yield 语句每次返回集合中的每个元素。 您可以通过 对每个 .。。下一语句

Yield语句可以在 Try 块内。 Try包含语句的块 Yield 可以有 Catch 块,并且可以有 Finally 块。 有关示例,请参阅迭代器中的 "Try 块 Visual Basic" 部分。

Yield语句不能位于 Catch 块或 Finally 块中。

如果在 For Each 迭代器函数外 (主体) 引发异常,则 Catch 不会执行迭代器函数中的块,但 Finally 会执行迭代器函数中的块。 CatchIterator 函数内的块仅捕获 iterator 函数内发生的异常。

部分信任情况

在部分信任的情况下(例如在网络共享上托管的应用程序),不 Try...Catch...Finally 会捕获在调用包含调用的方法之前出现的安全异常。 在以下示例中,当你将其放在服务器共享上并从该位置运行时,将产生错误 "SecurityException:请求失败"。 有关安全异常的详细信息,请参阅 SecurityException 类。

Try
    Process.Start("http://www.microsoft.com")
Catch ex As Exception
    MsgBox("Can't load Web page" & vbCrLf & ex.Message)
End Try

在这种部分信任情况下,必须将 Process.Start 语句放在单独的中 Sub 。 对的初始调用 Sub 将失败。 这样,便可以 Try...Catch 在包含的开始之前捕获它 Sub Process.Start 并生成安全异常。

示例

Try ... 的结构Catch .。。最后

下面的示例阐释了语句的结构 Try...Catch...Finally

Public Sub TryExample()
    ' Declare variables.
    Dim x As Integer = 5
    Dim y As Integer = 0

    ' Set up structured error handling.
    Try
        ' Cause a "Divide by Zero" exception.
        x = x \ y

        ' This statement does not execute because program
        ' control passes to the Catch block when the
        ' exception occurs.
        MessageBox.Show("end of Try block")
    Catch ex As Exception
        ' Show the exception's message.
        MessageBox.Show(ex.Message)

        ' Show the stack trace, which is a list of methods
        ' that are currently executing.
        MessageBox.Show("Stack Trace: " & vbCrLf & ex.StackTrace)
    Finally
        ' This line executes whether or not the exception occurs.
        MessageBox.Show("in Finally block")
    End Try
End Sub

从 Try 块调用的方法中的异常

在下面的示例中, CreateException 方法引发 NullReferenceException 。 生成异常的代码不在 Try 块中。 因此,该 CreateException 方法不会处理异常。 RunSample由于对方法的调用 CreateException 在块中,因此该方法会处理异常 Try

该示例包含 Catch 多个异常类型的语句,按从最具体到最常见的顺序排序。

Public Sub RunSample()
    Try
        CreateException()
    Catch ex As System.IO.IOException
        ' Code that reacts to IOException.
    Catch ex As NullReferenceException
        MessageBox.Show("NullReferenceException: " & ex.Message)
        MessageBox.Show("Stack Trace: " & vbCrLf & ex.StackTrace)
    Catch ex As Exception
        ' Code that reacts to any other exception.
    End Try
End Sub

Private Sub CreateException()
    ' This code throws a NullReferenceException.
    Dim obj = Nothing
    Dim prop = obj.Name

    ' This code also throws a NullReferenceException.
    'Throw New NullReferenceException("Something happened.")
End Sub

Catch When 语句

下面的示例演示如何使用 Catch When 语句根据条件表达式进行筛选。 如果条件表达式的计算结果为 True ,则块中的代码将 Catch 运行。

Private Sub WhenExample()
    Dim i As Integer = 5

    Try
        Throw New ArgumentException()
    Catch e As OverflowException When i = 5
        Console.WriteLine("First handler")
    Catch e As ArgumentException When i = 4
        Console.WriteLine("Second handler")
    Catch When i = 5
        Console.WriteLine("Third handler")
    End Try
End Sub
' Output: Third handler

嵌套 Try 语句

下面的示例包含 Try…Catch 包含在块中的语句 Try 。 内部 Catch 块引发了一个异常,该异常的 InnerException 属性设置为原始异常。 外部 Catch 块报告其自己的异常和内部异常。

Private Sub InnerExceptionExample()
    Try
        Try
            ' Set a reference to a StringBuilder.
            ' The exception below does not occur if the commented
            ' out statement is used instead.
            Dim sb As System.Text.StringBuilder
            'Dim sb As New System.Text.StringBuilder

            ' Cause a NullReferenceException.
            sb.Append("text")
        Catch ex As Exception
            ' Throw a new exception that has the inner exception
            ' set to the original exception.
            Throw New ApplicationException("Something happened :(", ex)
        End Try
    Catch ex2 As Exception
        ' Show the exception.
        Console.WriteLine("Exception: " & ex2.Message)
        Console.WriteLine(ex2.StackTrace)

        ' Show the inner exception, if one is present.
        If ex2.InnerException IsNot Nothing Then
            Console.WriteLine("Inner Exception: " & ex2.InnerException.Message)
            Console.WriteLine(ex2.StackTrace)
        End If
    End Try
End Sub

异步方法的异常处理

下面的示例阐释异步方法的异常处理。 若要捕获适用于异步任务的异常,该 Await 表达式位于 Try 调用方的块中,而在块中捕获该异常 Catch

在示例中取消注释 Throw New Exception 行以演示异常处理。 异常捕获于 Catch 块中,任务的 IsFaulted 属性设置为 True ,任务的 Exception.InnerException 属性设置为异常。

取消注释 Throw New OperationCancelledException 行以演示在取消异步进程时发生的情况。 异常捕获到 Catch 块中,任务的 IsCanceled 属性设置为 True 。 但是,在某些不适用于此示例的情况下,将 IsFaulted 设置为 True ,并将 IsCanceled 设置为 False

Public Async Function DoSomethingAsync() As Task
    Dim theTask As Task(Of String) = DelayAsync()

    Try
        Dim result As String = Await theTask
        Debug.WriteLine("Result: " & result)
    Catch ex As Exception
        Debug.WriteLine("Exception Message: " & ex.Message)
    End Try

    Debug.WriteLine("Task IsCanceled: " & theTask.IsCanceled)
    Debug.WriteLine("Task IsFaulted:  " & theTask.IsFaulted)
    If theTask.Exception IsNot Nothing Then
        Debug.WriteLine("Task Exception Message: " &
            theTask.Exception.Message)
        Debug.WriteLine("Task Inner Exception Message: " &
            theTask.Exception.InnerException.Message)
    End If
End Function

Private Async Function DelayAsync() As Task(Of String)
    Await Task.Delay(100)

    ' Uncomment each of the following lines to
    ' demonstrate exception handling.

    'Throw New OperationCanceledException("canceled")
    'Throw New Exception("Something happened.")
    Return "Done"
End Function


' Output when no exception is thrown in the awaited method:
'   Result: Done
'   Task IsCanceled: False
'   Task IsFaulted:  False

' Output when an Exception is thrown in the awaited method:
'   Exception Message: Something happened.
'   Task IsCanceled: False
'   Task IsFaulted:  True
'   Task Exception Message: One or more errors occurred.
'   Task Inner Exception Message: Something happened.

' Output when an OperationCanceledException or TaskCanceledException
' is thrown in the awaited method:
'   Exception Message: canceled
'   Task IsCanceled: True
'   Task IsFaulted:  False

在异步方法中处理多个异常

下面的示例阐释了在多个任务可能导致多个异常的情况中的异常处理。 Try块具有返回的 Await 任务的表达式 Task.WhenAll 。 当应用的三个任务完成时,任务完成 Task.WhenAll

三个任务中的每一个都会导致异常。 Catch块循环访问异常,这些异常在返回的任务的 Exception.InnerExceptions 属性中找到 Task.WhenAll

Public Async Function DoMultipleAsync() As Task
    Dim theTask1 As Task = ExcAsync(info:="First Task")
    Dim theTask2 As Task = ExcAsync(info:="Second Task")
    Dim theTask3 As Task = ExcAsync(info:="Third Task")

    Dim allTasks As Task = Task.WhenAll(theTask1, theTask2, theTask3)

    Try
        Await allTasks
    Catch ex As Exception
        Debug.WriteLine("Exception: " & ex.Message)
        Debug.WriteLine("Task IsFaulted: " & allTasks.IsFaulted)
        For Each inEx In allTasks.Exception.InnerExceptions
            Debug.WriteLine("Task Inner Exception: " + inEx.Message)
        Next
    End Try
End Function

Private Async Function ExcAsync(info As String) As Task
    Await Task.Delay(100)

    Throw New Exception("Error-" & info)
End Function

' Output:
'   Exception: Error-First Task
'   Task IsFaulted: True
'   Task Inner Exception: Error-First Task
'   Task Inner Exception: Error-Second Task
'   Task Inner Exception: Error-Third Task

另请参阅