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