共用方式為


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 區塊時,如果發生例外狀況 (Exception),則會按文字順序檢查每一個 Catch 陳述式,以判斷它是否會利用代表已擲回之例外狀況的 exception 來處理例外狀況。

exception

選擇項。 任何變數名稱。 exception 的初始值就是擲回的錯誤值。 與 Catch 搭配使用以指定攔截的錯誤。 如果省略,則 Catch 陳述式會攔截所有例外狀況。

type

選擇項。 指定類別篩選條件類型。 如果 exception 的值為 type 所指定的型別或衍生型別 (Derived Type),則識別項會繫結到例外狀況物件。

When

選擇項。 只有在 expression 評估為 True 時,具有 When 子句的 Catch 陳述式才會攔截例外狀況。 只有在檢查例外狀況的型別之後,才會套用 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 陳述式是由其後跟隨一個或多個指定各種例外狀況處理常式之 Catch 子句的 Try 區塊組成。 當 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 程式碼片段。在 [程式碼片段管理員] 中,依序展開 [程式碼模式 - If、For Each、Try Catch、Property 等] 和 [錯誤處理 (例外狀況)]。如需詳細資訊,請參閱 程式碼片段

Finally 區塊

如果必須先執行一或多個陳述式再結束 Try 結構,請使用 Finally 區塊。 控制項會先傳遞至 Finally 區塊,再從 Try…Catch 結構傳出。 即使 Try 結構內部的任何位置發生例外狀況 (Exception),也會執行這個動作。

Finally 區塊可用於執行即使發生例外狀況都必須執行的任何程式碼。 不論 Try...Catch 區塊如何結束,程式執行都會轉移到 Finally 區塊。

即使您的程式碼在 Try 或 Catch 區塊中遇到 Return 陳述式,Finally 區塊中的程式碼仍會執行。 在下列情況下,不會將控制項從 Try 或 Catch 區塊傳遞至對應的 Finally 區塊:

您不能明確執行傳輸到 Finally 區塊。 在 Finally 區塊以外的傳送之執行無效,除了透過例外狀況。

如果 Try 陳述式未包含至少一個 Catch 區塊,它必須包含一個 Finally 區塊。

提示

如果不需要攔截特定例外狀況,則 Using 陳述式的行為會像 Try…Finally 區塊,而且不論是以何種方式結束該區塊,都保證會處置 (Dispose) 資源。即使在未處理例外狀況的情況下也一樣。如需詳細資訊,請參閱 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 區塊中的程式碼可以將例外狀況正確報告給使用者,不論是透過安全執行緒記錄還是透過適當的訊息。 否則,例外狀況可能仍是未知。

用於方法

如果您將標記為與 用於初始化 修飾詞的方法,在方法中使用 等候 運算子。 使用 Await 運算子的陳述式暫停方法的執行,直到等候工作完成。 表示工作持續進行的工作。 當控制項與 Await 運算子時的工作之後,執行在相同方法復原。 如需詳細資訊,請參閱 非同步程式中的控制流程 (C# 和 Visual Basic)

用於方法傳回的工作在錯誤狀態可能會結束,指示其已完成因為未處理的例外狀況。 工作已取消的狀態可能也會結束,導致擲回等候運算式之外的 OperationCanceledException 。 若要攔截例外狀況的其中一種,可將與 Try 封鎖的工作的 Await 運算式並攔截例外狀況在 Catch 區塊。 範例會在本主題稍後會提供。

因為多個例外狀況指派給它,並查看管理工作可以在錯誤狀態。 例如,工作可能為呼叫的結果指派給 Task.WhenAll。 當您正在等候這些工作時,會攔截的例外狀況只能有一個例外狀況,因此,您無法預測哪個例外狀況會攔截它。 範例會在本主題稍後會提供。

Await 運算式不可以在 Catch 區塊或 Finally 區塊內。

Iterator

Iterator 函式或 Get 存取子對集合的自訂反覆項目。 Iterator 使用 yield 陳述式會傳回集合中的每個項目一次。 您可以使用 For Each...Next 陳述式 (Visual Basic)Iterator,請呼叫函式。

Yield 陳述式可以是 Try 區塊內。 包含 Yield 陳述式的 Try 區塊有 Catch 區塊,而且 Finally 區塊。 如需範例 Iterator (C# 和 Visual Basic) 「請參閱 Visual Basic 的 try 區塊>一節。

Yield 陳述式不可以在 Catch 區塊或 Finally 區塊內。

如果 For Each 主體 (在 Iterator 函式之外) 擲回例外狀況,在函式的 Catch Iterator 區塊,並不會執行,但在 Iterator 函式的 Finally 區塊執行。 在 Iterator 的函式中 Catch 區塊攔截發生在 Iterator 函式內的例外狀況。

部分信任情況

在部分信任的情況下,例如裝載在網路共用的應用程式,Try...Catch...Finally 不會攔截在叫用包含呼叫的方法前所發生的安全性例外狀況。 當置於伺服器共用並予以執行時,下列範例會產生錯誤:"System.Security.SecurityException: Request Failed"。如需安全性例外狀況的詳細資訊,請參閱 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 進行的初始呼叫將會失敗。 這會使得包含 Process.Start 的 Sub 開始之前,且在產生安全性例外狀況之前,讓 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

在下列範例中,CreateException 方法會擲回 NullReferenceException。 產生例外狀況的程式碼不在 Try 區塊中。 因此 CreateException 方法不會處理例外狀況。 由於對 CreateException 方法的呼叫是在 Try 區塊中進行的,因此RunSample 方法不會處理例外狀況。

範例包含許多例外狀況類型的 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 區塊中的 Try…Catch 陳述式。 內部 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 區塊有 Task.WhenAll 傳回的工作 Await 運算式。 工作完成時, 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

請參閱

參考

Err

Exit 陳述式 (Visual Basic)

On Error 陳述式 (Visual Basic)

Exception

Throw 陳述式 (Visual Basic)

概念

使用程式碼片段的最佳作法

例外狀況處理 (工作平行程式庫)