[C#] 自訂例外處理
Introduction
程式無法順利執行的原因很多,可能是資料問題、硬體問題、網路問題、記憶體不足或是檔案遺失等等問題,
也許在怎麼周密的程式,都難免周全,例外處理是一種機制,當例外發生時,我們可以發出必要訊息並處理
接下來後續的動作,比如說,資料庫的回傳數據不正確,造成程式錯誤,這時,程式接收到這個例外,也許,
會發個 e-mail 或是其他方式,通知管理員,並且還可以讓程式避免自動終止,或是將錯誤訊息直接 show 出。
常用的 try-catch 來幫助我們處理例外的發生。例外狀況很多,列出一些參考資料。
例外狀況 | 原因 |
ArgumentException | 當其中一個提供給方法的引數為無效時所擲回的例外狀況。 |
ArithmeticException | 為算術、轉型 (Casting) 或轉換作業中的錯誤擲回例外狀況。 |
DivideByZeroException | 嘗試將整數或小數值除以零時所擲回的例外狀況。 |
DllNotFoundException | DLL 匯入中所指定的 DLL 找不到時所擲回的例外狀況。 |
FormatException | 當引數的格式不符合叫用 (Invoke) 方法的參數規格時所擲回的例外狀況。 |
MissingFieldException | 當嘗試動態存取不存在的欄位時,所擲回的例外狀況。 |
OutOfMemoryException | 當沒有足夠的記憶體繼續執行程式時,所擲回的例外狀況。 |
OverflowException | 當檢查內容中的算數、轉型 (Casting) 或轉換作業發生溢位時所擲回的例外狀況。 |
NullReferenceException | 當嘗試解除 Null 物件的參考時,所擲回的例外狀況。 |
IndexOutOfRangeException | 嘗試使用陣列以外的索引來存取陣列的元素時所擲回的例外狀況。這個類別無法被繼承。 |
這邊只是冰山一角,請參考 MSDN 。
效能問題
我們必須透過設計,讓擲回例外狀況可能會對效能產生負面的影響。
以下範例參考 http://msdn.microsoft.com/zh-tw/library/ms229009.aspx
ex1
此範例包含一個方法,這個方法需要傳入一個字串型別的參數,若此方法傳遞 null 值給它時,
擲回例外狀況。如果經常呼叫此方法,它可能會對效能產生負面影響。
public class Doer
{
// Method that can potential throw exceptions often.
public static void ProcessMessage(string message)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
}
// Other methods...
}
ex2
修正範例1,判斷傳進來的參數是否為 null 值。
public class Doer
{
// Method that can potential throw exceptions often.
public static void ProcessMessage(string message)
{
if (message != null)
{
ProcessMessage("message");
}
}
}
當然,我還是覺得 method 可以加入註解說明,提醒要調用這個方法的使用者,說明傳入參數不可為 null 值,
若為 null 則丟出錯誤訊息。或是,不處理為 null 值的參數。
自訂例外類別
自訂例外狀況的標準做法,可以參考 設計自訂例外狀況。
class MyException : Exception, ISerializable
{
public MyException()
: base("show message") { }
public MyException(string message)
: base(message) { }
public MyException(string message, Exception inner)
: base(message, inner) { }
protected MyException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
}
若要丟出例外:
throw new MyException();
Exception 還可以攜帶更多資訊,以下列出參考。(Exception 成員)
成員 | 類別 | 說明 |
Data | 屬性 | 取得由索引鍵/值組所組成的集合,提供關於此例外狀況的額外使用者定義資訊。 |
HelpLink | 屬性 | 取得或設定與這個例外狀況相關聯說明檔的連結。 |
InnerException | 屬性 | 取得造成目前例外狀況的 Exception 執行個體。 |
Source | 屬性 | 取得或設定造成錯誤的應用程式或物件的名稱。 |
Message | 屬性 | 取得描述目前例外狀況的訊息。 |
GetBaseException | 方法 | 在衍生類別中覆寫時,傳回一或多個後續的例外狀況的根本原因 Exception。 |
GetObjectData | 方法 | 在衍生類別中覆寫時,使用例外狀況的資訊設定 SerializationInfo。 |
一個類別丟出例外一個類別捕捉例外
有時你未必知道使用者如何使用你的物件,有時候別人會以錯誤的方式來使用你的物件。
丟出例外的意義是:知道有甚麼事情可能發生,可以安排緊急的應變方式,而且例外通常是
由另一個物件丟出的。
TFileManager.cs
class TFileManager {
public static void OpenFile(string Path) {
try {
System.IO.File.Open(Path, System.IO.FileMode.Open);
}catch(System.IO.FileNotFoundException ex){
throw ex;
}
}
}
Program.cs
class Program {
static void Main(string[] args) {
try {
TFileManager.OpenFile("MyNote.txt");
}
catch (System.IO.FileNotFoundException) {
//...
//建立一個 MyNote.txt 文件。
//或是其他敘述。
Console.WriteLine("throw Exception.");
}
Console.ReadKey();
}
}
輸出結果
注意
- 小心建構子裡的例外
當例外發生在建構子時,我們該如何處理。
參考下面例子當例外發生時,試圖實例化該類別的陳述式最後就不會得到一個實例。
try{ CurrentExcuse = new Excuse(name); }catch{ ... //這邊你可以重新實例化,或是其他敘述。 // CurrentExcuse = new Excuse(); ... }
Link
三小俠 小弟獻醜,歡迎指教