共用方式為


例外狀況處理 (C# 程式設計手冊)

C# 程式設計人員會使用 try 區塊來分割可能受到例外狀況影響的程式代碼。 相關聯的 catch 區塊可用來處理任何產生的例外狀況。 finally 區塊包含程式碼,不論是否在 try 區塊中擲回例外狀況,例如釋放在 try 區塊中配置的資源。 try區塊需要一或多個相關聯的catch區塊,或finally區塊,或兩者。

下列範例顯示 try-catch 語句、 try-finally 語句和 try-catch-finally 語句。

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

缺少try區塊或catch區塊的finally區塊會導致編譯器錯誤。

「Catch」區塊

catch區塊可以指定要攔截的例外狀況類型。 類型規格稱為 例外狀況篩選條件。 例外狀況類型應該衍生自 Exception。 一般而言,除非您知道如何處理區塊中Exception可能擲回的所有例外狀況,或已在區塊結尾try包含 throw 語句,否則請勿指定catch為例外狀況篩選條件。

具有不同例外狀況類別的多個 catch 區塊可以鏈結在一起。 區塊 catch 會從程序代碼的上到下進行評估,但針對擲回的每個例外狀況,只會執行一個 catch 區塊。 會執行第一 catch 個區塊,指定所擲回例外狀況的確切類型或基類。 如果語句中存在沒有任何類型的區塊,且catch區塊未指定任何相符的例外類別,則會選擇catch區塊。 請務必先放置 catch 具有最特定(也就是最衍生的)例外狀況類別的區塊。

當下列條件成立時,攔截例外狀況:

  • 您已充分瞭解為何可能引發例外狀況,而且您可以實作特定復原措施,例如當您攔截 FileNotFoundException 物件時,提示使用者輸入新檔名。
  • 您可以建立並擲回新的更特定的例外。
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • 您想在進一步處理之前,先部分處理例外狀況。 在下列範例中,catch 區塊可用來在重新擲回例外狀況之前,新增一個條目至錯誤記錄檔。
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

您也可以指定 例外狀況篩選 條件,將布爾表達式新增至 catch 子句。 例外狀況篩選條件指出特定 catch 子句只有在該條件為 true 時才相符。 在下列範例中,這兩個 catch 子句都會使用相同的例外狀況類別,但會檢查額外的條件來建立不同的錯誤訊息:

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

一律傳 false 回的例外狀況篩選條件可用來檢查所有例外狀況,但無法處理這些例外狀況。 一般用途是記錄例外狀況:

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

LogException 方法總是傳回 false,沒有任何使用此例外篩選器的 catch 子句匹配。 catch 子句可以是一般的,使用 System.Exception,後續的子句可以處理更特定的例外狀況類別。

最終區塊

區塊 finally 可讓您清除區塊中 try 執行的動作。 如果 finally 區塊存在,它會在 try 區塊及任何相符的 catch 區塊之後執行,最後執行。 區塊 finally 總是會執行,無論是擲回例外狀況還是找到符合例外狀況類型的區塊 catch

區塊 finally 可用來釋放資源,例如檔案流、資料庫連接和圖形句柄,而不需等待執行時期的垃圾收集器完成對物件的完成作業。

在下列範例中,finally 區塊是用來關閉在 try 區塊中開啟的檔案。 請注意,在關閉檔案之前,會先檢查檔句柄的狀態。 try如果區塊無法開啟檔案,檔案句柄仍保持null的值,而finally區塊不會嘗試關閉它。 相反地,如果檔案在 區塊中 try 成功開啟,區塊 finally 就會關閉開啟的檔案。

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格中的例外狀況try 語句。 語言規格是 C# 語法和使用方式的最終來源。

另請參閱