建立和擲回例外狀況 (C# 程式設計手冊)
更新:2007 年 11 月
例外狀況可用於指出程式執行時所發生的錯誤。會建立描述錯誤的例外狀況物件,然後使用 throw 關鍵字「擲回」(Thrown)。然後執行階段會搜尋最適合的例外處理常式。
程式設計人員應該設計在下列一個或多個條件為 True 時擲回例外狀況:
方法無法完成本身定義的功能。
例如,方法的參數值無效:
static void CopyObject(SampleClass original) { if (original == null) { throw new System.ArgumentException("Parameter cannot be null", "original"); } }
在物件某種狀態下,對物件進行不當的呼叫。
例如可能會嘗試寫入唯讀檔案的範例。在物件狀態不允許作業的狀況下,會擲回 InvalidOperationException 的執行個體或依據此類別衍生的物件。這是擲回 InvalidOperationException 物件的方法範例:
class ProgramLog { System.IO.FileStream logFile = null; void OpenLog(System.IO.FileInfo fileName, System.IO.FileMode mode) {} void WriteLog() { if (!this.logFile.CanWrite) { throw new System.InvalidOperationException("Logfile cannot be read-only"); } // Else write data to the log and return. } }
當方法引數會造成例外狀況時。
在這種情況下,應攔截原始的例外狀況,並應建立 ArgumentException 執行個體。原始的例外狀況應該做為 InnerException 參數傳遞至 ArgumentException 的建構函式 (Constructor):
static int GetValueFromArray(int[] array, int index) { try { return array[index]; } catch (System.IndexOutOfRangeException ex) { System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex); throw argEx; } }
例外狀況會包含名為 StackTrace 的屬性。這個字串包含目前呼叫堆疊上方法的名稱,以及針對每個方法擲回例外狀況所在的檔案名稱及行號。Common Language Runtime (CLR) 會在出現 throw 陳述式 (Statement) 的位置自動建立 StackTrace 物件,因此例外狀況必須從堆疊追蹤應有的起始點擲回。
所有的例外狀況都包含名為 Message 的屬性。這個字串應該設定為說明例外狀況的原因。請注意,訊息文字中不應該放入安全性的敏感資訊。除了 Message 以外,ArgumentException 也包含名為 ParamName 的屬性,該屬性應設為引發例外狀況擲回的引數名稱。若為屬性 setter,則 ParamName 應設為 value。
公用和受保護的方法一旦未能完成預期的功能,即應擲回例外狀況。擲回的例外狀況類別,應該是符合錯誤狀況的最特定可用例外狀況。這些例外狀況應記載為類別功能的一部分,而且衍生類別 (Derived Class) 或更新後的類別也應該維持與原始類別相同的行為,以保有回溯相容性 (Backward Compatibility)。
擲回例外狀況時應該要避免的做法
下列清單會指出擲回例外狀況時應該要避免的做法:
例外狀況不應在一般執行時用來變更程式流程。例外狀況只應該用來報告和處理錯誤狀況。
例外狀況不應在擲回以外,做為傳回值或參數傳回。
請勿從自己的原始程式碼蓄意擲回 System.Exception、System.SystemException、System.NullReferenceException 或 System.IndexOutOfRangeException。
請勿建立可以在偵錯模式中擲回,但是不能在發行模式中擲回的例外狀況。若要在開發階段期間辨識執行階段錯誤,請改用 Debug Assert。
定義例外狀況類別
程式可以擲回 System 命名空間 (Namespace) 中的預先定義例外狀況類別 (除了之前所註明者),或是從 ApplicationException 衍生以建立其本身的例外狀況類別。衍生類別應至少定義四個建構函式:一個是預設建構函式、一個設定訊息屬性,一個則同時設定 Message 和 InnerException 屬性。第四個建構函式則是用來序列化例外狀況。新的例外狀況類別應該是可序列化的。例如:
[Serializable()]
public class InvalidDepartmentException : System.Exception
{
public InvalidDepartmentException() { }
public InvalidDepartmentException(string message) { }
public InvalidDepartmentException(string message, System.Exception inner) { }
// Constructor needed for serialization
// when exception propagates from a remoting server to the client.
protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) { }
}
除非新屬性提供的資料有助於解析例外狀況,否則不應隨意將新屬性加入至例外狀況類別。如果您將新屬性加入到衍生的例外狀況類別中,則應覆寫 ToString() 以傳回新增的資訊。
C# 語言規格
如需詳細資料,請參閱 C# 語言規格中的下列章節:
8.9.5 throw 陳述式
8.10 try 陳述式
16 例外狀況