處理和擲回例外狀況

應用程式必須能夠以一致的方式處理執行期間發生的錯誤。 Common Language Runtime 會提供一種模型,以統一的方式向應用程式通知錯誤。 所有 .NET Framework 作業都藉著擲回例外狀況 (Exception) 來表示失敗。

此主題包括下列章節:

  • .NET Framework 中的例外狀況

  • 例外狀況與 傳統錯誤處理方法

  • 執行階段如何管理例外狀況

  • 篩選執行階段例外狀況

  • 相關主題

  • 參考資料

.NET Framework 中的例外狀況

例外狀況是執行程式時遭遇的任何錯誤情況或意料不到的行為。 由於程式碼或所呼叫的程式碼 (例如,共用程式庫) 中有錯誤、找不到可用的作業系統資源、Common Language Runtime 遭遇非預期的意外情況 (例如,無法驗證程式碼) 等情況,就可能會發生例外狀況。 您的應用程式可以從其中某些情況復原,但無法從其他情況復原。 雖然您可以從大部分應用程式例外狀況復原,但您無法從大部分執行階段例外狀況復原。

在 .NET Framework 中,例外狀況是繼承自 System.Exception 類別的物件。 例外狀況會從問題發生的程式碼區域擲回。 例外狀況會在堆疊中往上傳遞,直到應用程式處理它或程式結束為止。

回到頁首

例外狀況與傳統錯誤處理方法

傳統上,語言的錯誤處理模型不是仰賴語言的獨特方式以偵測錯誤並為其找出處理常式,就是仰賴作業系統提供的錯誤處理機制。 執行階段則以下列功能實作例外處理 (Exception Handling):

  • 可以在不需顧慮產生或處理例外狀況所使用之語言的情況下來處理例外狀況。

  • 不需要任何特定語言語法以處理例外狀況,但允許各個語言定義本身的語法。

  • 允許例外狀況跨處理序 (Process) 和甚至電腦界限來擲回。

例外狀況提供許多其他錯誤告知方法 (如傳回碼) 所不及的優點。 凡有失敗就會告知。 無效值就不會傳遍整個系統。 您也不一定要檢查傳回碼。 可以輕易地例外處理程式碼加入以增加程式的可靠性。 最後,執行階段的例外處理比 Windows 架構的 C++ 錯誤處理還要快速。

因為執行的執行緒會例常周遊 Managed 和 Unmanaged 程式碼區塊,執行階段可以在 Managed 或者 Unmanaged 程式碼中擲回或攔截例外狀況。 Unmanaged 程式碼可以包含 C++ 樣式的 SEH 例外狀況和 COM 架構的 HRESULTS 兩者。

執行階段如何管理例外狀況

執行階段會根據例外狀況物件和程式碼保護區塊來使用例外處理模型。 Exception 物件在例外狀況發生時被建立以表示它。

執行階段會為各個可執行檔建立例外狀況資訊表格。 可執行檔的各個方法在例外狀況資訊表中具有例外處理資訊的相關陣列 (可能是空白的)。 陣列的各個項目會描述程式碼的保護區塊、與那程式碼相關的任何例外狀況篩選條件,和任何例外處理常式 (catch 陳述式)。 這個例外狀況表格非常有效率,並且例外狀況未發生時,不會導致處理器時間或記憶體使用方面的效能降低。 您只有在例外狀況發生時會使用資源。

例外狀況資訊表顯示保護區塊的例外處理常式的四種類型:

  • 每當區塊結束 (不論經由一般控制流程或因為未處理的例外狀況而發生) 都會執行的 finally 處理常式

  • 如果例外狀況發生,但未在一般控制流程完成時執行,必定會執行的 Fault 處理常式

  • 按類型篩選的處理常式,處理指定類別或其任何衍生類別的任何例外狀況

  • 使用者篩選的處理常式,執行使用者指定的程式碼以判斷例外狀況是否應該藉由處理常式來處理,或應該傳遞至下一個保護區塊

各個語言都依照其規格實作這些例外處理常式。 例如,Visual Basic 會透過 catch 陳述式中的變數比較 (使用 When 關鍵字),提供對使用者篩選處理常式的存取。C# 則不實作使用者篩選處理常式。

當例外狀況發生時,執行階段開始兩階段的程序:

  1. 執行階段會在陣列中搜尋執行下列作業的第一個保護區塊:

    • 保護含有目前執行中指令的區域

    • 含有例外處理常式或含有篩選條件 (以處理例外狀況) 的區域

  2. 如果有相符的狀況發生,執行階段會建立 Exception 物件以描述例外狀況。 執行階段接著執行例外狀況發生的陳述式和處理例外狀況的陳述式之間的所有 finally 或 Fault 陳述式。 請注意,例外處理常式的順序也是十分重要的:位於較內層的例外處理常式會優先進行評估。 也請注意,例外處理常式可以存取攔截例外狀況的常式的區域變數和區域記憶體,但任何在例外狀況擲回時產生的中繼值會遺失。

    如果在目前方法中沒有相符狀況發生,執行階段會搜尋目前方法的各個呼叫端,並且在堆疊中一路向上繼續搜尋。 如果沒有符合的呼叫端,執行階段會讓偵錯工具存取例外狀況。 如果偵錯工具並未附加至例外狀況,執行階段會引發 AppDomain.UnhandledException 事件。 如果沒有這個事件的接聽程式 (Listener),執行階段會傾印堆疊追蹤並結束應用程式。

回到頁首

篩選執行階段例外狀況

您可以藉著型別,或者藉著使用者定義的準則,篩選您要攔截和處理的例外狀況。

按類型篩選的處理常式會管理特定例外狀況的類型 (或從它衍生的類別)。 下列範例顯示設計來攔截特定例外狀況 (在此例中為 FileNotFoundException) 的按類型篩選處理常式。

Catch e As FileNotFoundException
    Console.WriteLine("[Data File Missing] {0}", e)
catch (FileNotFoundException e)
{
    Console.WriteLine("[Data File Missing] {0}", e);
}
catch (FileNotFoundException^ e)
{
    Console::WriteLine("[Data File Missing] {0}", e);
}

使用者篩選的例外處理常式根據您對例外狀況定義的需求,攔截並處理例外狀況。 如需以這種方式篩選例外狀況的詳細資訊,請參閱使用 Catch 區塊中的特定例外狀況

回到頁首

相關主題

標題

說明

Exception 類別和屬性

描述例外狀況物件的項目。

例外狀況階層架構

描述大部分例外狀況所衍生自的例外狀況。

例外處理基礎觀念

解釋如何使用 Catch、Throw 和 Finally 陳述式來處理例外狀況。

處理例外狀況的最佳作法

描述處理例外狀況的建議方法。

處理 COM Interop 例外狀況

描述如何處理 Unmanaged 程式碼中擲回的和攔截的例外狀況。

HOW TO:對應 HRESULT 和例外狀況

描述例外狀況在 Managed 和 Unmanaged 程式碼之間的對應。

回到頁首

參考資料

System.Exception

System.ApplicationException

System.SystemException