2011年2月20日 星期日

4-10 Try…End Try錯誤處理程序

        在過去ASP時代,程式碼中只有On Error可用來捕捉或處理錯誤,而ASP.NET中,除了On Error可用之外,還可以利用Try …End Try來進行錯誤處理。

        Try…End Try』這個新玩意兒,看起來好像很有學問的樣子,其實用起來相當的簡單,基本的指令架構如下:
Try
   [ tryStatements ]
[ Catch [ exception [ As type ] ] [ When expression ] 
   [ catchStatements ] ]
[ Exit Try ]
...
[ Finally
   [ finallyStatements ] ]
End Try

        上面是『Try…Catch…Finally』在.NET Framework中完整的定義,對於程式設計師,它的內涵就是:
Try
   可能發生錯誤的程式
[ Catch [ exception [ As type ] ] [ When expression ]
   發生錯誤時,要執行的指令
[ Exit Try ]若下了Exit Try 指令,則跳出Try…End Try結構
[ Catch [ exception [ As type ] ] [ When expression ]
   Catch 可以有很多個,程式會依照 When 後面的expression來決定執行哪一個Catch敘述
[ Finally
   只要一進入Try敘述中,不管有沒有錯誤或從Try敘述中的哪一部份離開都執行的程式
End Try

底下是實例:
Public Sub TryExample()
   Dim x As Integer = 5   '定義兩個整數
   Dim y As Integer = 0

   Try   ' 進入Try結構,從這裡開始捕捉錯誤
      x =x/ y   '發生錯誤→除以零

   Catch ex As Exception When y = 0   
'當錯誤產生時,若Y=0就執行這段錯誤處理程式
      resp(“發生錯誤,除以零!!!”)  
   Finally
      Beep()   '只要進入錯誤處理程序,完成後就Beep一聲
   End Try
End Sub

        這樣的錯誤處理結構,比起過去的On Error 看似複雜許多,但是程式設計上卻較結構化,程式設計師不再需要因為On Error Goto敘述GotoGoto去,造成閱讀和撰寫的困擾而傷腦筋。

        我們看一個實例,請開啟一個Web From,在上面佈置兩個TextBox、一個Button和一個Label
       
        並在Run這個按鈕的Click事件裡,撰寫底下的程式碼:
完整範例請參考Chapter02\TryError\Default.aspx
0001:    Private Sub Run_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Run.Click
0002:        Dim n1, n2 As Single
0003:
0004:        Try '開始Try...End Try 迴圈
0005:            '這裡是可能發生錯誤的(想要捕捉錯誤的)敘述
0006:            n1 = Me.NumA.Text / Me.NumB.Text
0007:            n2 = Me.NumB.Text / Me.NumA.Text
0008:
0009:        Catch ex As Exception When Me.NumB.Text = 0
0010:            '當發生錯誤,且NumB.Text=0時執行...
0011:            Me.result.Text += "<br>-->發生錯誤(B)" & ex.Message
0012:
0013:        Catch ex As Exception When Me.NumA.Text = 0
0014:            '當發生錯誤,且NumA.Text=0時執行...
0015:            Me.result.Text += "<br>-->發生錯誤(A)" & ex.Message
0016:
0017:        Catch ex As Exception
0018:            '當發生錯誤時執行...
0019:            Me.result.Text += "<br>-->發生錯誤:" & ex.Message
0020:
0021:        Finally '只要進入錯誤迴圈即執行
0022:            Me.result.Text += "<br>-->執行過 Finally..."
0023:
0024:        End Try '開始Try...End Try 迴圈
0025:
0026:        Me.result.Text += "<br>-->n1 (A/B)" & n1
0027:        Me.result.Text += "<br>-->n2 (B/A)" & n2
0028:    End Sub


        從第424行是一段完整的Try…End Try迴圈,第57行是我們想要捕捉的錯誤可能發生的位置(我們判斷有可能使用者輸入0,導致除以零錯誤),當錯誤發生在這裡時,就會被Try…End Try迴圈捕捉。

        91113151719都是當錯誤發生時,要處理的對應程序,我們看第9行的例子:
Catch ex As Exception When Me.NumB.Text = 0


        當錯誤發生,且『Me.NumB.Text = 0』時,則執行911行的程式。(很有趣的事情是,在.NET Framework上,這段程式永遠不會被執行,因為居然沒有除以零錯誤!很怪?待會解釋…)

        如果發生錯誤時,不是第913行的『Catch ex As Exception When Me.NumB.Text = 0』和『Catch ex As Exception When Me.NumA.Text = 0』,則會處理第17行『Catch ex As Exception』以後的敘述。

        Exception』傳回錯誤處理程序的物件,ex.Message 傳回錯誤訊息,而ex.Source則傳回發生錯誤的程式碼來源。

        我們實際看執行例子,首先,在欄位中輸入73,這個例子比較沒有爭議,計算結果直接顯示出來,整個過程中沒有發生錯誤,因此不會有捕捉錯誤的訊息,但是請注意,依舊會執行到程式中的『Finally』部分:

        但是當我們把AB改成底下這樣,錯誤就發生了:

        這時候,由於輸入的B是『DEF』,並非一個數字,因此會被程式第17行的『Catch ex As Exception』例外處理程序所捕捉到,然後執行第18行顯示出錯誤訊息(從字串 "DEF" 轉換為型別 'Double' 是無效的)與發生位置(Microsoft.VisualBasic)

        請注意,當您輸入的值是英文字的時候,並不會被第913行的例外處理程序捕捉到,因為,當時的數值並非0,而是文字,所以處理的程序是第17行,然而,當我們真的輸入0時,又會如何呢?

        這就是剛才提過挺有趣的部分,在.NET Framework中,居然不會有『除以零錯誤』,請注意,當我們把3/0時,結果並不會發生錯誤,因此第91317行的錯誤處理程序完全派不上用場,只有第21行的『Finally』依舊老實的被執行了(記得嗎?只要進入錯誤處理程序,即使不發生錯誤,依舊會執行Finally後的敘述)

        .NET Framework中,3/0的結果是→『正無窮大』!!!
正無窮大』實際在記憶體內的表示為『1.#INF』,『正無窮大』為呼叫ToString傳回的結果。
負無窮大』實際在記憶體內的表示為『-1.#INF』,『負無窮大』為呼叫ToString傳回的結果。


        好樣的,.NET Framework還真是神奇,我們試試看另外一個狀況,我們把0除以0,看看結果如何?

        程式照常執行,但是顯示出來的結果是『不是一個數字』。您會發現與傳統的程式設計有點不同,.NET Framework中捕捉了除以零的狀況(應該說是允許其發生),而將其賦予可呈現的值。
『不是一個數字』實際在記憶體內的表示為『-1.#IND』,『不是一個數字』為呼叫ToString傳回的結果。


        從上面這個例子,可以看到Try…End Try結構的用法,在每個Try…End Try之中,一定要有至少一個Catch敘述,否則會發生錯誤,而Finally則不一定需要,另外Try…End Try敘述不可與On Error敘述同時存在,儘管Visual Basic.NET對這兩個敘述都支援。

沒有留言:

張貼留言