2013年9月11日 星期三

[轉貼] 自訂例外處理 (Exception)

出處:http://www.dotblogs.com.tw/atowngit/archive/2009/12/06/12298.aspx


Introduction
程式無法順利執行的原因很多,可能是資料問題、硬體問題、網路問題、記憶體不足或是檔案遺失等等問題,
也許在怎麼周密的程式,都難免周全,例外處理是一種機制,當例外發生時,我們可以發出必要訊息並處理
接下來後續的動作,比如說,資料庫的回傳數據不正確,造成程式錯誤,這時,程式接收到這個例外,也許,
會發個 e-mail 或是其他方式,通知管理員,並且還可以讓程式避免自動終止,或是將錯誤訊息直接 show 出。
常用的 try-catch 來幫助我們處理例外的發生。例外狀況很多,列出一些參考資料。
例外狀況原因
ArgumentException當其中一個提供給方法的引數為無效時所擲回的例外狀況。
ArithmeticException為算術、轉型 (Casting) 或轉換作業中的錯誤擲回例外狀況。
DivideByZeroException嘗試將整數或小數值除以零時所擲回的例外狀況。
DllNotFoundExceptionDLL 匯入中所指定的 DLL 找不到時所擲回的例外狀況。
FormatException當引數的格式不符合叫用 (Invoke) 方法的參數規格時所擲回的例外狀況。
MissingFieldException當嘗試動態存取不存在的欄位時,所擲回的例外狀況。
OutOfMemoryException當沒有足夠的記憶體繼續執行程式時,所擲回的例外狀況。
OverflowException當檢查內容中的算數、轉型 (Casting) 或轉換作業發生溢位時所擲回的例外狀況。
NullReferenceException當嘗試解除 Null 物件的參考時,所擲回的例外狀況。
IndexOutOfRangeException嘗試使用陣列以外的索引來存取陣列的元素時所擲回的例外狀況。這個類別無法被繼承。
 這邊只是冰山一角,請參考 MSDN 。


效能問題
我們必須透過設計,讓擲回例外狀況可能會對效能產生負面的影響。
ex1
此範例包含一個方法,這個方法需要傳入一個字串型別的參數,若此方法傳遞 null 值給它時,
擲回例外狀況。如果經常呼叫此方法,它可能會對效能產生負面影響。
01public class Doer
02{
03    // Method that can potential throw exceptions often.
04    public static void ProcessMessage(string message)
05    {
06        if (message == null)
07        {
08            throw new ArgumentNullException("message");
09        }
10    }
11    // Other methods...
12}
ex2
修正範例1,判斷傳進來的參數是否為 null 值。
01public class Doer
02{
03    // Method that can potential throw exceptions often.
04    public static void ProcessMessage(string message)
05    {
06        if (message != null)
07        {
08            ProcessMessage("message");
09        }
10    
11}

當然,我還是覺得 method 可以加入註解說明,提醒要調用這個方法的使用者,說明傳入參數不可為 null 值,
若為 null 則丟出錯誤訊息。或是,不處理為 null 值的參數。

自訂例外類別
自訂例外狀況的標準做法,可以參考 設計自訂例外狀況
01class MyException : Exception, ISerializable
02{
03    public MyException()
04        base("show message") { }
05    public MyException(string message)
06        base(message) { }
07    public MyException(string message, Exception inner)
08        base(message, inner) { }
09    protected MyException(SerializationInfo info, StreamingContext context)
10        base(info, context) { }
11}

若要丟出例外:
1throw new MyException();

Exception 還可以攜帶更多資訊,以下列出參考。(Exception 成員)
成員類別說明
Data屬性取得由索引鍵/值組所組成的集合,提供關於此例外狀況的額外使用者定義資訊。
HelpLink屬性取得或設定與這個例外狀況相關聯說明檔的連結。
InnerException屬性取得造成目前例外狀況的 Exception 執行個體。
Source屬性取得或設定造成錯誤的應用程式或物件的名稱。
Message屬性取得描述目前例外狀況的訊息。
GetBaseException方法在衍生類別中覆寫時,傳回一或多個後續的例外狀況的根本原因 Exception
GetObjectData方法在衍生類別中覆寫時,使用例外狀況的資訊設定 SerializationInfo

一個類別丟出例外一個類別捕捉例外
有時你未必知道使用者如何使用你的物件,有時候別人會以錯誤的方式來使用你的物件。
丟出例外的意義是:知道有甚麼事情可能發生,可以安排緊急的應變方式,而且例外通常是
由另一個物件丟出的。
TFileManager.cs
1class TFileManager {
2        public static void OpenFile(string Path) {
3            try {
4                System.IO.File.Open(Path, System.IO.FileMode.Open);
5            }catch(System.IO.FileNotFoundException ex){
6                throw ex;
7            }
8        }
9    }

Program.cs
01class Program {
02    static void Main(string[] args) {
03        try {
04            TFileManager.OpenFile("MyNote.txt");
05        }
06        catch (System.IO.FileNotFoundException) {
07            //...
08            //建立一個 MyNote.txt 文件。
09            //或是其他敘述。
10            Console.WriteLine("throw Exception.");
11        }
12 
13        Console.ReadKey();
14    }
15}

輸出結果
tmp

注意
  • 小心建構子裡的例外
當例外發生在建構子時,我們該如何處理。
參考下面例子當例外發生時,試圖實例化該類別的陳述式最後就不會得到一個實例
1try{
2    CurrentExcuse = new Excuse(name);  
3}catch{
4    ...
5    //這邊你可以重新實例化,或是其他敘述。
6    // CurrentExcuse = new Excuse();
7    ...
8}

Link

沒有留言:

張貼留言