共用方式為


建立和擲回例外狀況

例外狀況可用來指出執行程式時發生錯誤。 會建立描述錯誤的例外狀況物件,。 運行時間接著會搜尋最相容的例外狀況處理程式。

當下列一或多個條件成立時,程式設計人員應該擲回例外狀況:

  • 方法無法完成其定義的功能。 例如,如果方法的參數具有無效的值:

    static void CopyObject(SampleClass original)
    {
        _ = original ?? throw new ArgumentException("Parameter cannot be null", nameof(original));
    }
    
  • 基於物件狀態進行不當的函數呼叫。 其中一個範例可能嘗試寫入唯讀檔案。 如果對象狀態不允許作業,請丟出 InvalidOperationException 實例或基於此類別衍生的物件。 下列程式代碼是擲回 InvalidOperationException 物件的方法範例:

    public class ProgramLog
    {
        FileStream logFile = null!;
        public void OpenLog(FileInfo fileName, FileMode mode) { }
    
        public void WriteLog()
        {
            if (!logFile.CanWrite)
            {
                throw new InvalidOperationException("Logfile cannot be read-only");
            }
            // Else write data to the log and return.
        }
    }
    
  • 當方法的自變數造成例外狀況時。 在此情況下,應該攔截原始例外狀況,並建立 ArgumentException 實例。 原始例外狀況應傳遞至 ArgumentException 建構函式做為 InnerException 參數:

    static int GetValueFromArray(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    

    注意

    上述範例示範如何使用 InnerException 屬性。 它是刻意簡化的。 在實務上,您應該先檢查索引是否在範圍內,再使用它。 當您呼叫參數的成員時,如果發生了您無法事先預料的例外狀況,您可以使用這個技巧來包裝這些例外狀況。

例外狀況包含名為 StackTrace的屬性。 此字串包含目前呼叫堆疊上方法的名稱,以及每個方法擲回例外狀況的檔名和行號。 共通語言執行平台 (CLR) 會從 StackTrace 語句所在的點自動建立 throw 物件,因此例外狀況必須從堆疊追蹤應該開始的點擲回。

所有例外狀況都包含名為 Message的屬性。 此字串應設定為說明例外狀況的原因。 對安全性敏感的信息不應該放在消息正文中。 除了 Message之外,ArgumentException 還包含名為 ParamName 的屬性,該屬性應設定為造成擲回例外狀況的自變數名稱。 在屬性 setter 中,ParamName 應設定為 value

每當公共和受保護的方法無法完成其預定的功能時,就會擲回例外狀況。 擲回的例外狀況類別是符合錯誤條件的最特定例外狀況。 這些例外狀況應記錄為類別功能的一部分,而原始類別的衍生類別或更新應保留相同的行為,以保持回溯相容性。

拋出例外狀況時應避免的事項

下列清單會識別擲回例外狀況時應避免的做法:

  • 請勿使用例外狀況來變更程式流程,作為一般執行的一部分。 使用例外狀況來報告及處理錯誤狀況。
  • 例外狀況不應以傳回值或參數的形式傳回,而不是擲回。
  • 請勿在您自己的原始程式碼中故意擲回 System.ExceptionSystem.SystemExceptionSystem.NullReferenceExceptionSystem.IndexOutOfRangeException
  • 請勿建立可在偵錯模式中擲回但無法以發行模式擲回的例外狀況。 若要在開發階段識別運行時間錯誤,請改用偵錯判斷提示。

工作傳回方法中的例外狀況

使用 async 修飾詞宣告的方法在例外狀況方面有一些特殊考慮。 async 方法中擲回的例外狀況會儲存在傳回的工作中,並且直到等待該工作時才會出現。 如需預存例外狀況的詳細資訊,請參閱 異步例外狀況

建議您先驗證自變數,並擲回任何對應的例外狀況,例如 ArgumentExceptionArgumentNullException,再輸入方法的異步部分。 也就是說,這些驗證例外狀況應該會在工作開始之前同步出現。 下列程式碼片段展示了一個範例,其中,若拋出例外狀況,ArgumentException 例外狀況會同步出現,而 InvalidOperationException 則會儲存在返回的任務中。

// Non-async, task-returning method.
// Within this method (but outside of the local function),
// any thrown exceptions emerge synchronously.
public static Task<Toast> ToastBreadAsync(int slices, int toastTime)
{
    if (slices is < 1 or > 4)
    {
        throw new ArgumentException(
            "You must specify between 1 and 4 slices of bread.",
            nameof(slices));
    }

    if (toastTime < 1)
    {
        throw new ArgumentException(
            "Toast time is too short.", nameof(toastTime));
    }

    return ToastBreadAsyncCore(slices, toastTime);

    // Local async function.
    // Within this function, any thrown exceptions are stored in the task.
    static async Task<Toast> ToastBreadAsyncCore(int slices, int time)
    {
        for (int slice = 0; slice < slices; slice++)
        {
            Console.WriteLine("Putting a slice of bread in the toaster");
        }
        // Start toasting.
        await Task.Delay(time);

        if (time > 2_000)
        {
            throw new InvalidOperationException("The toaster is on fire!");
        }

        Console.WriteLine("Toast is ready!");

        return new Toast();
    }
}

定義例外狀況類別

程式可以在 System 命名空間中擲回預先定義的例外狀況類別(除非先前已注意到),或藉由衍生自 Exception來建立自己的例外狀況類別。 衍生類別應該至少定義三個建構函式:一個無參數建構函式、一個設定訊息屬性,另一個同時設定 MessageInnerException 屬性。 例如:

[Serializable]
public class InvalidDepartmentException : Exception
{
    public InvalidDepartmentException() : base() { }
    public InvalidDepartmentException(string message) : base(message) { }
    public InvalidDepartmentException(string message, Exception inner) : base(message, inner) { }
}

當他們提供的數據有助於解析例外狀況時,將新屬性新增至例外狀況類別。 如果將新的屬性新增至衍生的例外狀況類別,則應該覆寫 ToString() 以傳回新增的資訊。

C# 語言規格

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

另請參閱