Try Catch Finally概述

  相信有很多人都知道Try-Catch這個東西,只要是寫在Try與Catch裡面的程式發生錯誤,就會跳到Catch的地方,最後就一定會執行finally區段(如果有寫的話).如此方便的做法,使用也相當的普遍,但也常被討論它的效能問題.

  相信有很多人都知道Try-Catch這個東西,只要是寫在TryCatch裡面的程式發生錯誤,就會跳到Catch的地方,最後就一定會執行finally區段(如果有寫的話).如此方便的做法,使用也相當的普遍,但也常被討論它的效能問題,記得早期曾看過一段程式碼,可能當時工程師不知道如何去判斷使用者輸入的文字是否為數字(C#並沒有IsNumeric,但可以用Double.TryParseInt32.TryParse等的方式去判斷),所以這段程式碼所用的方式是用Try Catch去包一段程式,如果因為非數字而Parse失敗,就跳到Catch,所以這種效能自然差到不行,這個錯誤的例子是依懶TryCatch來做判斷,需記得TryCatch不是拿來這麼用的,只是該程式並沒有辨法使用TryParse或是CharIsNumber,因為執行平台是在是.Net1.0,Double也必需到1.1才支援,後續改用其它方式去判斷,雖然程式碼變多,但效能比用TryCatch觸發Exception來的快很多.

 

TryParse支援版本及參考清單

型別

.Net支援()版本以上

參考

Boolean

2.0

Boolean.TryParse Method

Byte

2.0

Byte.TryParse Method

Char

2.0

Char.TryParse Method

DateTime

2.0

DateTime.TryParse Method

Decimal

2.0

Decimal.TryParse Method

Double

1.1

Double.TryParse Method

SByte

2.0

SByte.TryParse Method

Single

2.0

Single.TryParse Method

IntXX

2.0

Int32.TryParse Method

UIntXX

2.0

UInt32.TryParse Method

備註

Char可以用IsNumber去判斷是否為數字,.Net1.1以上就可以用了.參考MSDN上的說明.

使用TryParse判斷字串是否為數值

*別誤解TryParse是用來判斷數值.它是用來轉型(Parse)並回傳成功或失敗的結果,DateTime來說,TryParse就是判斷字串是否轉換日期格式成功.

 

  

  TryCatch最常見的賴人寫法就是直接抓通用的Exception,例如 :

Try

{

  Code here…..

}

Catch (Exception ex)

{

  MessageBox.Show(ex.Message);

}

  其實Exception有相當的多種類,例如SqlExceptionArgumentNullException,有興趣的人可以參考MSDN上所提供的資訊,依自己所需要的情況去抓取Exception訊息,例如某段對DB操作的程式碼,如果有發生DB的錯誤,需要將錯誤寫,Log,其它Exception就不需要,就可以用SqlException去抓到DB相關的錯誤.

  可是TryCatch因為效能的關係,可別將它一股腦的在程式的每個地方都用TC包起來,如果確定不會出問題的,就不用包了,TC用在一些難以預期的意外上或是刻意要抓取的例外,就很好用,例如DB的連線,沒人可以保證你的程式在與DB連線時,100%不可能斷線,或是IO寫檔到一半,磁碟機斷線或是掛了,這個程式碼很難防,好不容易寫了一堆程式碼來防範,結果下次又因為別的狀況又掛了,此時還是TryCatch好用.

  即然提到它的缺點類別,那它在一些特殊用法時,它會是什麼樣的情況,例如巢式TryCatch,呼叫端與被呼叫端均有TC包起來,如果發生Exception,那會是那個TC被觸發?以下用幾個簡單的例子來說明 :

 

Ex 1 :

try

{

int i = 0;

        int k = 10 / i;

        try

       {

            int a = 0;

            int b = 10 / a;

}

       catch

       {

            MessageBox.Show("inside");

}

}

catch

{

MessageBox.Show("Out Side");

}

 

  紅色字的部份,就是會發生錯誤的地方,當執行到第一個k=10/i,就會發生錯誤,就會跳到Out Sidecatch,inside的部份並不會執行到.

 

Ex 2 :

try

{

    try

    {

        int a = 0;

        int b = 10 / a;

     }

    catch

    {

        MessageBox.Show("inside");

     }

     int i = 0;

     int k = 10 / i;

}

catch

{

     MessageBox.Show("Out Side");

}

  Ex2的做法類似Ex1,不過這次把裡面的TC往上移,這次執行就會執行到第二層的TC,所以也會觸發Exception,但只會觸發insideException,OutSide的並不會被觸發,Out Side的部份則是執行到k=10/i,才會觸發,也就是說,第二層TC觸發後,並不會直接跳到外層的TC,它還是會往下執行.

 

EX3 :

private void button4_Click(object sender, EventArgs e)

{

     try

    {

          Ex2();

     }

    catch

    {

            MessageBox.Show("From click");

     }

}

 

 

private void Ex2()

{

    int i = 0;

    int k = 10 / i;

}

呼叫function的程式寫法也很普遍,但如果今天被呼叫的function發生錯誤,而且沒有包TC,用呼叫端去包function,也是同樣可以catch到錯誤,以這個例子來說,還是可以抓到Message”嘗試以零除。”.

 

EX4 :

private void button7_Click(object sender, EventArgs e)

{

     try

    {

            Ex5();

     }

    catch (Exception ex)

    {

            MessageBox.Show(ex.Message);

     }

}

 

private void Ex5()

{

     try

    {

        int i = 0;

        int k = 10 / i;

     }

    catch (Exception ex)

    {

            throw new Exception("Error : "+ex.Message);

     }

}

  如果有時候希望回丟的訊息除了原本的Message,能再加上額外的訊息供判斷,例如錯誤單號或是檔案,就能更清楚的找到錯誤資料,這時就可以用throw new Exception的方式來丟資訊,這個例子所Show出來的Message就會是”Error : 嘗試以零除。

  Exception可以抓到的不只是目前例外狀況的訊息而已,也可取得造成錯誤的程式或物件名稱等,finally也是很重要的一環,不管有沒有觸發Exception,finally區段一定都會執行到,所以善用TCException所提供的資訊,相信能更容易的掌握問題點,Try-Catch-Finally所包住的程式效能並不會有多大的影響,效能只有在觸發Exception時才會比較差,所以該用的時候還是要用,別把TryCatch當文章開頭提的一樣,用來當判斷用,那效能真的是會出人命,而且Exception是可以抓到所有的Exception沒有錯,但效能會差一點,如果能明確指定是那一種Exception,效能會比較好,例如以下寫法.

try

{

        Code here.

}

catch (SqlException se)

{

        Section 1

}

catch (Exception ex)

{

        Section 2

}

  如果是發生SqlException相關的錯誤,那就會執行Section 1這段,就不會執行Section 2,如果發生的是SqlException外的,那才會去執行Section 2.

那為什麼明確指定Exception種類的效能會比較好呢,因為它就不用再到共同Excption去一個一個找出錯誤的資訊,減少查詢範圍.

 

參考資訊 :

MSDN Exception屬性

MSDN 理和擲回例外狀況

MSDN 結構化例外處理概觀

Visual Basic .Net的效能最佳化