在任何應用系統開發中
異常管理對開發人員來說都是一個關鍵領域
作為一個開發人員
你應該采用一種合適的
能讓你編寫健壯且高質量代碼的異常管理策略
如果使用得當
異常管理將是一個很強大的概念而且使你的開發工作變的很容易
然而
一個不合適的異常處理將會使你的應用系統性能降低
在你鑽研這些之前
要先搞清楚異常管理是什麼
這點很重要
一般來說異常就表示
打破系統預定的假設
異常
和
錯誤
是不一樣的
為了解釋清楚
我們來看兩個例子
示例一
我們假設你試圖向一個文件寫入數據
而你的應用程序也認為這個文件在正確的路徑上
如果不在
就會拋出一個異常
而話說回來
如果你的職責是跟蹤此文件
那麼代碼裡還有(找不到文件的)異常那將是一個不好的編碼習慣
這種情況應該被校驗代碼處理(而不是異常)
示例二
再讓我們假設一個一般的ASP
NET程序中
你正試圖更新數據庫中所有必需的字段
你的應用程序認為此數據庫連接可用
假設實際上這個連接是不可用的……拋出異常是一個解決方案
而我們又把話說回來
如果更新數據庫的必填字段時出現有幾個值為空的字段
那拋出異常就沒有必要了
這些處理應該由校驗代碼完成
如何處理異常
作為一個開發人員
你應該感受到通過try
catch
finally塊來構建一個結構化異常處理機制的優點
NET框架提供了一大堆異常處理層次來處理不同種類的異常
所有的異常都繼承自Exception(基類)
你可以通過繼承來實現自定義錯誤處理以擴展異常處理機制
不幸的是
很多開發人員都誤用了這種架構能力
一個隨時要記著的事是當一個異常發生在運行時時(這個架構)應該如何運作?一般有以下三種情況
忽略異常
讓它在調用棧裡上升而被其它的catch塊捕獲
捕獲異常
同時為你的應用程序執行必要的動作
如果你不想再次在異常中拋出異常的話
捕獲異常
並用其它異常覆蓋它
這樣和你的應用程序有更密切的關系
異常覆蓋是為了避免打破(架構中的)抽象層次
你可以通過你拋出的異常的InnerException屬性指定原異常是什麼
這樣就可以把你現有的異常用一個新的異常來覆蓋了(更與你系統有關的)
為了了解異常覆蓋
讓我們來看一個能引起IOException異常的方法
你可以在應用級別使用LoadingException 或 FailtoLoadInfoException來覆蓋原有的IOException異常
這樣比把底層的IOException給用戶看到要來的好些
一個應用程序的異常處理框架應該有以下幾種(要求)
探測異常
執行代碼清除
內部異常覆蓋
內部異常替換
記錄並報告錯誤信息
建立能被外部監視的事件以幫助系統操作
在開始你應該建立一個一致的
健壯的異常管理架構
在你所有的系統中應該很好的封裝並抽象其記錄和報告等的細節
好的習慣
以下列出一些不錯的提示/建議供你在(設計)異常處理(時)參考
拋出異常要不小的代價
所以
你應該盡可能地在
異常情況
下進行異常處理
不要去控制正規邏輯流程
比如
以下代碼
void EmpExits(string EmpId)
{
// search for employee
if(dr
Read(EmpId) ==
) // no record found
{
throw(new Exception(
Emp Not found
));
}
}
應該用以下代碼
bool EmpExits(string EmpId)
{
// search for employee
if(dr
Read(EmpId) ==
) // no record found
{
return false;
}
}
避免在循環中捕獲異常
如果實在是要捕獲
那把整個循環都放在try/catch塊裡
采用標准try/catch/finally異常處理方式進行處理
這在托管代碼裡是被推薦的
最後的Finally塊確保異常事件中的資源都被釋放掉了
比如
SqlConnection conn = new SqlConnection(
);
try
{
conn
Open();
// some operation
// some additional operations
}
catch(Exception ex)
{
// handle the exception
}
finally
{
if (conn != null && conn
State == ConnectionState
Open)
conn
Close(); // closing the connection
}
盡可能的用校驗代碼而避免使用異常
如果你知道一個可避免的條件可能會出現
那就讓它避免
比如
在執行任何操作以前
檢查空值(VB裡是Nothing)
這樣可以避免使用異常以及性能問題
以下代碼
double result =
;
try
{
result = firstVal/secondVal;
}
catch(System
Exception e)
{
// handling the zero divided exception
}
應該替換成
double result =
;
if(secondVal != null && secondVal >
)
{
result = firstVal/secondVal;
}
else
{
result = System
Double
NaN;
}
不要為沒有必要的情況(原文
reasons)拋出異常
再次拋出異常的開銷和實例化一個新異常的開銷一樣的大
同時再次拋出異常使程序調試工作增加難度
比如
try
{
// Perform some operations
in case of throw an exception…
}
catch (Exception e)
{
// Try to handle the exception with e
throw;
}
推薦的處理不同的錯誤的不同的方法是實現一系列的catch塊
這看起來好像沒有什麼
但可以讓你的異常處理從特殊走向普通
比如捕獲一個和文件有關的異常明顯要比捕獲一個FileNotFoundException
DirectoryNotFoundException
SecurityException
IOException
UnauthorizedAccessException甚至最後的基類Exception
好的多
ADO
NET 的錯誤應該通過 SqlException 或 OleDbException來處理
使用ConnectionState屬性來檢查連接是否可用要比異常處理好的多
要常使用Try/Finally
Finally提供了關閉連接的機會
Using語句可以達到同樣的效果
用指定的處理程序來處理異常
在一些情況下如果你知道一些可能的異常那就用相應的異常處理類
比如
try
{}
catch(SqlException sqlexp) // specific exception handler
{}
catch(Exception ex) // Generic exception handler
{}
你的異常處理架構應該可以探測異常並在內部將其覆蓋
(或是)使用其它異常將其替換
或是為監視系統而記錄和報告這些信息
推薦大家使用 Microsoft
s patterns & practices 團隊 提供的Exception Management Application Block
這是一個簡單且可擴展的框架用於記錄異常信息到事件文件中
你可以自定義它
把日志記錄到其它數據源中同時不影響你系統的代碼
Exception Management Application Block都是一些由patterns & practices團隊開發的很好的代碼
並且已經徹底地被Microsoft labs給測試過了
From:http://tw.wingwit.com/Article/program/net/201311/13404.html