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

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

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 值給它時,

擲回例外狀況。如果經常呼叫此方法,它可能會對效能產生負面影響。

01 public 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 值。

01 public 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 值的參數。

 

自訂例外類別

自訂例外狀況的標準做法,可以參考 設計自訂例外狀況

01 class 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 }

 

若要丟出例外:

1 throw new MyException();

 

Exception 還可以攜帶更多資訊,以下列出參考。(Exception 成員)

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

 

一個類別丟出例外一個類別捕捉例外

有時你未必知道使用者如何使用你的物件,有時候別人會以錯誤的方式來使用你的物件。

丟出例外的意義是:知道有甚麼事情可能發生,可以安排緊急的應變方式,而且例外通常是

由另一個物件丟出的。

TFileManager.cs

1 class 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

01 class 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         Console.ReadKey();
13     }
14 }

 

輸出結果

tmp

 

注意

  • 小心建構子裡的例外

當例外發生在建構子時,我們該如何處理。

參考下面例子當例外發生時,試圖實例化該類別的陳述式最後就不會得到一個實例

1 try{
2     CurrentExcuse = new Excuse(name);   
3 }catch{
4     ...
5     //這邊你可以重新實例化,或是其他敘述。
6     // CurrentExcuse = new Excuse();
7     ...
8 }

 

Link

try-catch-finally (C# 參考)

例外狀況的設計方針

設計自訂例外狀況

處理和擲回例外狀況

Exception 類別和屬性