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

C# 程式設計人員使用 try 區塊分割可能受到例外狀況影響的程式碼。 相關聯的 catch 區塊用來處理任何產生的例外狀況。 無論 try 區塊是否擲回例外狀況,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。 一般情況下,請勿將 Exception 指定為例外狀況篩選條件,除非您知道如何處理 try 區塊中可能擲回的所有例外狀況,或您已在 catch 區塊的結尾包含 throw 陳述式

多個有不同的例外狀況類別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 子句。 例外狀況篩選條件表示,僅在該條件為 true 時才符合特定的 catch 子句。 在下列範例中,兩個 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 區塊

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

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# 語法及用法的限定來源。

另請參閱