天天看點

[畢業生的商業軟體開發之路]C#異常處理

近期開始接觸到在校學生、高校實習生和畢業生,在此說一下筆者對這些徘徊在職場門口的學生一些建議,希望能給這些初學者進入軟體開發行業帶來一些幫助,使得畢業生能更順利的進入軟體開發公司開始職場生涯,人生來一個完美的轉彎。

---------------------------------------------------------

<b>using 文法結構</b>

        在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 

}  

finally 

    ( (System.IDisposable)stream).Dispose();  

        C#編譯器會将using結構翻譯成一個“try{ } finally{ }”結構,并在finally塊中調用檔案流對象的Dispose方法,這個方法就能關閉檔案流,釋放所有的資源。即使其中的功能代碼發生錯誤,抛出異常,檔案流仍然能關閉來釋放資源。

        從這裡可以看出using文法結構具有一定的異常處理功能,它沒有捕獲異常,但能感覺異常,并進行了一些處理來減少異常帶來的負面影響。

        C#中的using文法結構是針對System.IDisposable接口的,System.Idisposable接口隻聲明了一個成員“void Dispose( )”,用于釋放對象所占有的重要資源。任何實作了System.IDisposable接口的對象都能被用上using結構,比如檔案流、資料庫連接配接、網絡連接配接等等。

    開發軟體一定要有足夠的風險意識,認識到商業軟體在各種複雜的情況下運作,必然會出現各種各樣的風險和錯誤,這些風險和錯誤需要進行處理。無視風險和錯誤,假設一切都很和諧是很危險的思想。

<b>主動處理錯誤</b>

    程式開發中可以主動處理錯誤和被動處理錯誤,主動處理錯誤就是進行寫代碼進行功能執行前的檢查,最常見也是最有效的手段就是在方法體開頭處檢查方法參數是否正确。主動檢查程式運作速度快,而且系統更穩定,而且将風險消滅在萌芽之中,避免後期的錯誤大爆發,是以是優先采用的風險處理方式。

    例如下面的代碼就是主動處理錯誤。

public int Div( int a , int b )  

    // 檢查參數,若b為0,則必然會爆被0除的錯誤,提前處理錯誤。  

    if (b == 0)  

    {  

        return 0;  

    }  

    return a / b;  

這段代碼就是主動的檢查參數是否正确,盡早制止錯誤的發生。

<b>被動異常處理</b>

    主動處理錯誤的方式很可能會有遺漏,C#中可以采用異常捕獲機制來被動的處理錯誤。

    在說明異常前首先得講講程式的調用堆棧的概念。其實基本上所有的程式設計語言都有調用堆棧的功能。例如在程式運作時,方法F1調用了方法F2,F2在某個瞬時又調用了方法F3,而方法F3在某個時刻調用了方法F4。則此時刻存在“F1 | F2 | F3 | F4”的調用堆棧。如下圖所示,此時程式的代碼呈現為一種洋蔥一樣的按照方法分層的結構,越靠裡層就越是底層代碼。

<a target="_blank" href="http://blog.51cto.com/attachment/201108/093632842.gif"></a>

    C#中的異常就是程式子產品發生錯誤的資訊,抛出異常就是程式通知系統程式發生錯誤了,這種異常是全局性,從抛出點開始,沿着調用堆棧,一層層的向上推動,越往上,影響面越大,若調用堆棧上某層代碼能主動捕獲并處理這個異常,該異常就消失掉了,系統就能正常運作,若一直沒有代碼能主動捕獲異常,則該異常就會一直捅到了.NET架構層面。

    例如在F1、F2、F3、F4構成的調用堆棧中個,如果方法F4内部主動抛出了一個異常,該異常首先抛給了方法F3,若F3不處理異常則該異常又抛給了F2,若F2還是沒有處理則繼續抛給了F1,若F1沒有處理則直接抛給了.NET架構系統本身了。

    這有點像上訪,村裡的農民覺得不滿到找村長上訪,村長不處理接着到縣裡上訪,縣裡不處理則到省裡上訪,省裡不處理則最後跑到中央上訪,中央總是以簡單粗暴的方式處理任何上訪的。[袁永福版權所有]

    不過凡事驚動中央是不好的,.NET架構就是.NET應用程式的中央,.NET架構本身處理沒有被程式處理的異常會彈出如下的程式錯誤對話框

<a target="_blank" href="http://blog.51cto.com/attachment/201108/093701575.jpg"></a>

    對于該對話框,若點選“繼續”按鈕則程式或許還能接着運作,但可能出于一種不穩定的狀态;點選“退出”按鈕則立即無條件的退出程式,這可能導緻資料未儲存。

    一旦顯示出系統級錯誤對話框,則該程式的穩定性可靠性是非常的差,應當盡量避免這種情況。這就需要在調用堆棧中的某些合适層面的方法中添加異常處理來應付底層方法抛出的異常。

    在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架構而成為系統級的錯誤。是以開發程式時必須加上合适的異常處理。

    由于異常是被動的處理錯誤,而且執行過程消耗了不少資源,是以主動防禦錯誤永遠比被動處理錯誤要好。在實踐中可以考慮将兩者都用上,做好雙保險,這樣程式才能可靠穩定。[袁永福版權所有]

     本文轉自xdesigner 51CTO部落格,原文連結:http://blog.51cto.com/xdesigner/635718,如需轉載請自行聯系原作者