-
Try...Catch...Finally 语句 (Visual Basic)
用于处理给定代码段中可能出现的某些或所有错误,而同时代码仍保持运行。
Try
[ tryStatements ]
[ Exit Try ]
[ Catch [ exception [ As type ] ] [ When expression ]
[ catchStatements ]
[ Exit Try ] ]
[ Catch ... ]
[ Finally
[ finallyStatements ] ]
End Try
部件
术语 |
定义 |
tryStatements |
可选。 可能发生错误的语句。 可以是复合语句。 |
Catch |
可选。 允许使用多个 Catch 块。 如果在处理 Try 块时发生异常,则会按文本顺序检查每条 Catch 语句,以确定它是否处理异常,exception 代表已引发的异常。 |
exception |
可选。 任何变量名称。 exception 的初始值是引发的错误的值。 它将与 Catch 一起使用以指定所捕获的错误。 如果省略,则 Catch 语句将捕获所有异常。 |
type |
可选。 指定类筛选器的类型。 如果 exception 的值采用的是 type 所指定的类型或者派生类型,则该标识符将绑定到异常对象。 |
When |
可选。 带有 When 子句的 Catch 语句只会在 expression 的计算结果为 True 时捕获异常。 When 子句仅在检查异常类型之后应用,expression 可以引用表示异常的标识符。 |
expression |
可选。 必须可隐式转换为 Boolean。 说明一般筛选器的任何表达式。 通常用来根据错误号进行筛选。 它与 When 关键字一同使用,以指定捕获错误时的环境。 |
catchStatements |
可选。 用于处理在关联的 Try 中发生的错误的语句。 可以是复合语句。 |
Exit Try |
可选。 用于退出 Try...Catch...Finally 结构的关键字。 将继续执行紧跟在 End Try 语句后面的代码。 Finally 语句仍将被执行。 不允许在 Finally 块中使用。 |
Finally |
可选。 当执行过程离开 Try...Catch 语句的任何部分时,总是会执行 Finally 块。 |
finallyStatements |
可选。 在所有其他错误处理结束后执行的语句。 |
End Try |
终止 Try...Catch...Finally 结构。 |
备注
如果预计特定代码部分会发生特定异常,请将该代码放到 Try 块中,并使用一个 Catch 块来保留控制焦点,如果发生异常则对其进行处理。
Try…Catch 语句由一个 Try 块后跟一个或多个 Catch 子句构成,这些子句指定各种异常处理的程序。 如果 Try 块中引发异常,则 Visual Basic 将查找处理异常的 Catch 语句。 如果未找到匹配的 Catch 语句,则 Visual Basic 会检查调用当前方法的方法,然后会遍历调用堆栈。 如果找不到 Catch 块,则 Visual Basic 会向用户显示一条有关未经处理的异常的消息并停止执行程序。
可以在 Try…Catch 语句中使用多个 Catch 语句。 如果执行此操作,则 Catch 子句的顺序很重要,因为会按顺序检查它们。 将先捕获特定程度较高的异常,而不是特定程度较小的异常。
下面的 Catch 语句条件是最不特定的,将捕获从 Exception 类派生的所有异常。 在捕获所有预期的特定异常之后,通常应将其中一个变量用作 Try...Catch...Finally 结构中的最后一个 Catch 块。 控制流绝不会到达遵循以下任一变化的 Catch 块。
-
type 为 Exception,例如:Catch ex As Exception
-
语句不包括 exception 变量,例如: Catch
当 Try…Catch…Finally 语句嵌套在另一个 Try 块中时,Visual Basic 首先检查最里面 Try 块中的每个 Catch 语句。 如果没有找到匹配的 Catch 语句,则继续搜索外部 Try…Catch…Finally 块的 Catch 语句。
Try 块中的局部变量将无法在 Catch 块中使用,因为它们是独立的块。 如果要在多个块中使用某个变量,请在 Try...Catch...Finally 结构之外声明该变量。
提示
Try…Catch…Finally 语句可用作 IntelliSense 代码段。 在代码段管理器中,展开“代码模式 - 如果,对于每一个,尝试捕获,属性,等等”,然后展开“错误处理(异常)”。 有关更多信息,请参见 如何:插入 IntelliSense 代码段。
Finally 块
如果在退出 Try 结构之前必须运行一个或多个语句,则可以使用 Finally 块。 控制权在即将传递到 Try…Catch 结构外之前,将传递到 Finally 块。 即使在 Try 结构内部的任何位置发生异常也是这样。
Finally 块可用于运行即使有例外也必须执行的任何代码。 将控制权传递给 Finally 块,与 Try...Catch 块的退出方式无关。
Finally 块中的代码将运行,即使在 Try 或 Catch 块中遇到 Return 语句。 在以下情况中控制权不会从 Try 或 Catch 块传递到相应的 Finally 块:
-
在 Try 或 Catch 块中遇到 End 语句。
-
在 Try 或 Catch 块中引发了 StackOverflowException。
显式将执行传输到 Finally 块是无效的。 除了通过异常之外,将执行从 Finally 块中转移出来是无效的。
如果 Try 语句不包含至少一个 Catch 块,它必须包含 Finally 块。
提示
如果不需要捕捉特定异常,则 Using 语句的行为与 Try…Finally 块一样,且无论以何种方式退出块,都保证会处置资源。 发有未经处理的异常,也是如此。 有关更多信息,请参见 Using 语句 (Visual Basic)。
异常参数
Catch 块 exception 参数是 Exception 类或派生自 Exception 类的类的实例。 Exception 类实例与 Try 块中发生的错误相对应。
Exception 对象的属性可帮助您确定异常的原因和位置。 例如,StackTrace 属性列出导致异常的被调用方法,帮助您找到错误在代码中发生的位置。 Message 返回一条描述异常的消息。 HelpLink 返回指向关联的帮助文件的链接。 InnerException 返回引发当前异常的 Exception 对象,或如果没有原始 Exception,返回 Nothing。
使用 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 块中的代码可以将异常正确报告给用户,无论通过线程安全日志记录还是相应的消息。 否则,异常可能仍是未知的。
部分信任的情形
在部分信任的情况下(如网络共享上承载的应用程序),Try...Catch...Finally 将不会捕获在调用包含该调用的方法之前发生的安全异常。 当将下面的示例放置在服务器共享上并从此处运行时,将生成错误“System.Security.SecurityException: 请求失败”。有关安全异常的更多信息,请参见 SecurityException 类。
Try
Process.Start("https://www.microsoft.com")
Catch ex As Exception
MsgBox("Can't load Web page" & vbCrLf & ex.Message)
End Try
在这种部分信任的情况下,您必须将 Process.Start 语句放在单独的 Sub 中。 对 Sub 的初次调用将失败。 这使得 Try...Catch 能够在包含 Process.Start 的 Sub 启动并产生安全异常之前捕获它。
示例
下面的示例阐释了 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
下面的示例演示中,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 语句筛选条件表达式。 如果条件表达式计算为 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…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
' 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