using 語法結構
在C#中,關鍵字using出了可以引用命名空間外,還可以使用using結構來實現一定的異常處理.語法結構為"using( ) { }".例如以下代碼就演示了using結構.
using (System.IO.FileStream stream
= new System.IO.FileStream("c:\\a.txt", System.IO.FileMode.Create)) {
stream.WriteByte((byte)2); }
在字段代碼中,using後面的園括號中打開文件創建了一個文件流對象,然後再後面的花括號的代碼塊中向這個文件輸出一個字節,然後就沒有其他代碼了.
文件流是一種很重要的資源,打開後必須被關閉,否則就會資源洩露,在上面的代碼中應該補上代碼"stream.Close( )"來關閉文件流.但實際上面的代碼是安全的,不會出現資源洩露問題,這是因為采用了using語法結構.
上述代碼其功能等價於以下代碼
System.IO.FileStream stream
= new System.IO.FileStream("c:\\a.txt", System.IO.FileMode.Create);
try {
stream.WriteByte((byte)2); }
finally {
( (System.IDisposable)stream).Dispose();
}
C#編譯器會將using結構翻譯成一個"try{ } finally{ }"結構,並在finally塊中調用文件流對象的Dispose方法,這個方法就能關閉文件流,釋放所有的資源.即使其中的功能代碼發生錯誤,拋出異常,文件流仍然能關閉來釋放資源.
從這裡可以看出using語法結構具有一定的異常處理功能,它沒有捕獲異常,但能感知異常,並進行了一些處理來減少異常帶來的負面影響.
C#中的using語法結構是針對System.IDisposable接口的,System.Idisposable接口只聲明了一個成員"void Dispose( )",用於釋放對象所占有的重要資源.任何實現了System.IDisposable接口的對象都能被用上using結構,比如文件流、數據庫連接、網絡連接等等.
異常處理結構
開發軟件一定要有足夠的風險意識,認識到商業軟件在各種復雜的情況下運行,必然會出現各種各樣的風險和錯誤,這些風險和錯誤需要進行處理.無視風險和錯誤,假設一切都很和諧是很危險的思想.
主動處理錯誤
程序開發中可以主動處理錯誤和被動處理錯誤,主動處理錯誤就是進行寫代碼進行功能執行前的檢查,最常見也是最有效的手段就是在方法體開頭處檢查方法參數是否正確.主動檢查程序運行速度快,而且系統更穩定,而且將風險消滅在萌芽之中,避免後期的錯誤大爆發,因此是優先采用的風險處理方式.
例如下面的代碼就是主動處理錯誤.
public int Div( int a , int b )
{
// 檢查參數,若b為0,則必然會爆被0除的錯誤,提前處理錯誤.
if (b == 0)
{
return 0;
}
return a / b;
}
這段代碼就是主動的檢查參數是否正確,盡早制止錯誤的發生.
被動異常處理
主動處理錯誤的方式很可能會有遺漏,C#中可以采用異常捕獲機制來被動的處理錯誤.
在說明異常前首先得講講程序的調用堆棧的概念.其實基本上所有的編程語言都有調用堆棧的功能.例如在程序運行時,方法F1調用了方法F2,F2在某個瞬時又調用了方法F3,而方法F3在某個時刻調用了方法F4.則此時刻存在"F1 | F2 | F3 | F4"的調用堆棧.如下圖所示,此時程序的代碼呈現為一種洋蔥一樣的按照方法分層的結構,越靠裡層就越是底層代碼.
C#中的異常就是程序模塊發生錯誤的信息,拋出異常就是程序通知系統程序發生錯誤了,這種異常是全局性,從拋出點開始,沿著調用堆棧,一層層的向上推動,越往上,影響面越大,若調用堆棧上某層代碼能主動捕獲並處理這個異常,該異常就消失掉了,系統就能正常運行,若一直沒有代碼能主動捕獲異常,則該異常就會一直捅到了.NET框架層面.
例如在F1、F2、F3、F4構成的調用堆棧中個,如果方法F4內部主動拋出了一個異常,該異常首先拋給了方法F3,若F3不處理異常則該異常又拋給了F2,若F2還是沒有處理則繼續拋給了F1,若F1沒有處理則直接拋給了.NET框架系統本身了.
這有點像上訪,村裡的農民覺得不滿到找村長上訪,村長不處理接著到縣裡上訪,縣裡不處理則到省裡上訪,省裡不處理則最後跑到中央上訪,中央總是以簡單粗暴的方式處理任何上訪的.[袁永福版權所有]
不過凡事驚動中央是不好的,.NET框架就是.NET應用程序的中央,.NET框架本身處理沒有被程序處理的異常會彈出如下的程序錯誤對話框
對於該對話框,若點擊"繼續"按鈕則程序或許還能接著運行,但可能出於一種不穩定的狀態;點擊"退出"按鈕則立即無條件的退出程序,這可能導致數據未保存.
一旦顯示出系統級錯誤對話框,則該程序的穩定性可靠性是非常的差,應當盡量避免這種情況.這就需要在調用堆棧中的某些合適層面的方法中添加異常處理來應付底層方法拋出的異常.
在C#中使用"throw"關鍵字拋出以上,以下代碼就演示了拋出異常.
public int F1() {
thrownewException("這裡發生異常了"); }
這個方法中就使用throw關鍵字主動拋出了一個異常.在C#中所有的異常都是某個底層方法主動拋出來的.[袁永福版權所有]
注意方法F1定義為需要返回一個整數數值,若方法體中沒有return語句編譯不通過的,但使用throw語句時可以壓住這個規定.
在C#中使用"try{ }catch{ }finally{ }"結構來處理異常,以下代碼就演示了如何處理異常
public void HandleException(int a, int b)
{
try
{
// 進入能捕獲異常的狀態
F1();
}
catch (Exception ext)
{
// 若發生異常,在此捕獲異常,執行這段代碼
System.Windows.Forms.MessageBox.Show(ext.Message);
}
finally
{
// 不管有沒有發生異常,本段代碼都運行
Console.WriteLine("完成了處理");
}
}
在關鍵字"try"後面的代碼塊一般放置方法的功能性代碼,此時系統時刻檢查是否有拋出異常,若拋出異常則立即捕獲它,然後跳轉到關鍵字"catch"後面的代碼塊中處理異常.而無論是否發生異常,關鍵字"finally"後面的代碼塊都會執行的,這段代碼一般用於本方法的善後工作,比如釋放在工作過程中申請的重要資源等.Catch塊和finally塊是可選的,也可以寫成"try{ } catch { }"或者"try{ } finally{ }".
對於"try{ } catch{ }"結構,程序會捕獲異常並處理掉,使得異常不再上訪.
對於"try{ } finally{ }"結構,程序會感知異常,做一些處理,但不會捕獲異常,異常仍然會接著上訪.
使用異常處理,就能讓底層方法拋出的異常被及時的處理掉而不至於一路捅到.NET框架而成為系統級的錯誤.因此開發程序時必須加上合適的異常處理.
由於異常是被動的處理錯誤,而且執行過程消耗了不少資源,因此主動防御錯誤永遠比被動處理錯誤要好.在實踐中可以考慮將兩者都用上,做好雙保險,這樣程序才能可靠穩定.