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

C# 程式設計人員使用 try 區塊分割可能受到例外狀況影響的程式碼。 相關聯的 catch 區塊用來處理任何產生的例外狀況。 Finally區塊包含的程式碼會在區塊中 擲回例外狀況時執行,例如釋放在 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 區塊沒有 catchfinally 區塊會造成編譯器錯誤。

catch 區塊

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

具有不同例外狀況類別的多個 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 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 區塊

finally 區塊可讓您清除 try 區塊中執行過的動作。 如果有的話,finally 區塊會最後執行,在 try 區塊和任何符合的 catch 區塊之後。 finally區塊一律會執行、是否擲回例外狀況,或 catch 找到符合例外狀況類型的區塊。

finally 區塊可以用來釋放資源,例如檔案資料流、資料庫連接及圖形控點,不必等待執行階段的記憶體回收行程完成物件。 如需詳細資訊,請參閱 Using 語句

在下例中,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# 語法及用法的限定來源。

另請參閱