|
大家知道,即使程序員抱有最好的愿望,而且計劃工作做得非常周密,也無法避免代碼出現錯誤。實際上可能出現的程序錯誤是很多的,但是它們基本上可以分為兩種類型:一種是編譯錯誤;另一種是運行期錯誤。編譯錯誤是指使得Visual Bacsic(下面簡稱VB)的編譯器無法對代碼進行編譯的錯誤。如果一個過程中包含了編譯錯誤,VB將不執行該過程,并且我們也不能向用戶提供帶有編譯錯誤的運行期版本應用程序,大多數編譯錯誤是句法錯誤造成的。
一、VB的編譯選項
VB有兩個設置項會在很大程度上影響我們創建非常堅實的代碼的能力。一個設置項是Compile On Demand(按需要進行編譯),另一個設置項是Background Compile(后臺編譯)。可以打開Options對話框,選定General選項卡,然后對這兩個設置項進行設置,如下圖1所示。當選定Compile On Demand時,如果單擊工具欄上的Run按鈕,或者按F5鍵,VB并不全面編譯我們的項目。相反,只在引用過程時,才對這些過程進行編譯。使用Compile On Demand,通常可使比較大的項目或者速度較慢的計算機上的項目能夠更快地啟動運行,但是它也會產生某些不被注意的編譯錯誤。
在發現和糾正所有編譯錯誤之前,不能將項目編譯成.exe或.dll之類的可發布文件,因此,選定Compile On Demand并不能夠發布帶有編譯錯誤的代碼。但是,選定Compile On Demand后,會導致編譯錯誤隨著時間的推移而不斷增加,從而在最后試圖進行全面編譯時,迫使我們對代碼進行大量的糾錯。如果在IDE中調試項目,VB常常必須停止(不只是暫停)運行,以便進行糾錯操作。這使得調試正在運行的項目時對大量編譯錯誤的糾正操作變得非常麻煩。如果能夠在合理的時間內全面編譯項目,那么可以考慮關閉Compile On Demand。也可以使Compile On Demand保持選定狀態,但是要定期按Ctrl+F5鍵,以便重新運行我們的項目。這使我們在編程時能夠定期糾正編譯錯誤,而不必一次性糾正大量的編譯錯誤。
圖1 編譯時選中Compile On Demand和Background Compile兩個選項
二、Err對象
在能夠編寫有效的錯誤處理代碼之前,我們必須了解VB的Err對象,這是個運行期對象,它包含了關于最新錯誤的信息。當程序運行時遇到一個錯誤,或者當我們使用Err對象的Raise方法故意引發一個錯誤時,便形成Err對象的屬性。當遇到On Error語句(比如On Error Resume Next),并且在使用Exit Sub、Exit Function或Exit Property語句退出一個過程后,Error對象的屬性值就被清除。若要顯式清除Err對象,可以調用它的Clear方法。下表1列出了Err對象的屬性。
屬性 | 說明 |
| Number | 用于標識該錯誤的專用號碼 |
| Source | 當前VB項目的名字 |
| Description | 表義性的錯誤消息。如果某個錯誤沒有這個字符串,本屬性就會指明"應用程序定義的錯誤或對象定義的錯誤" |
| HelpFile | 與錯誤相關的VB 幫助文件所在的驅動器、路徑和文件名 |
| HelpContext | VB 幫助文件用于該錯誤的上下文ID |
| LastDLLError | 在32位Microsoft Windows操作系統上,上次調用動態鏈接庫(DLL)的系統錯誤代碼。LastDllError屬性是只讀屬性 |
三、錯誤處理程序的類型
將一個項目當作已經編譯的程序運行時,未捕獲的錯誤會造成致命的后果,它們會導致程序終止運行。必須盡一切努力防止發生這種情況。若要防止代碼中的錯誤中斷代碼的運行(并終止已編譯程序的運行),我們可以創建錯誤處理程序以捕獲代碼中的錯誤。當捕獲一個錯誤后,VB并不顯示出錯消息,也不終止代碼的運行。相反,我們編寫的專門用來處理錯誤的代碼則開始運行。每個過程都應該擁有錯誤處理程序,而不管它包含多大的代碼量。最好在代碼中放入一個On Error語句,作為代碼的第一行,放在緊靠過程標題的后面和變量說明的前面。如果一個過程的錯誤能夠以這種方式出現,就應該在過程的開頭用突出的注釋來明確說明這一行為特性。
若要捕獲錯誤,基本上可以使用下面兩種方法:
當出現錯誤時,使用On Error GoTo,轉移到別的代碼上去執行。
使用On Error Resume Next語句,不中斷代碼的執行,也不轉移到別的代碼上去執行,而是忽略該錯誤。
可以在一個過程中創建多個錯誤處理程序,但每次只能激活一個錯誤處理程序。VB將最新的On Error語句中指明的處理程序視為已經激活的錯誤處理程序。切換一個過程中的不同位置上的錯誤處理程序,往往是很有好處的,理解各個錯誤處理程序如何運行,是利用這一功能的關鍵。
1、使用On Error Resume Next以忽略錯誤
對錯誤進行處理的最簡單(和最危險)的方法是使用On Error Resume Next語句。On Error Resume Next語句規定,代碼中的錯誤將完全被忽略,存在錯誤的代碼行被跳過,然后繼續執行下一個語句。例如,下面這個過程存在一個運行期錯誤(即一個被0除的錯誤),它由On Error Resume Next錯誤處理程序來處理:
| Private Sub cmdGenerateError_Click() '* Purpose: Test On Error Resume Next On Error Resume Next Debug.Print 10 / 0 End Sub |
Debug.print語句產生了一個被0除的錯誤。但是,由于存在一個已經激活的錯誤處理程序(由On Error Resume Next指定),因此該錯誤被忽略,并在下一個語句(即End Sub語句)上恢復執行。錯誤被忽略并不意味著我們無法知道錯誤已經發生。當一個語句產生了一個錯誤之后,盡管沒有顯示出錯消息,Err對象仍然包含關于該錯誤的信息。
2、使用On Error GoTo轉移執行的代碼流
除非我們捕獲了一個意料之外的錯誤,比如上面代碼中的那種錯誤,否則忽略代碼中的錯誤是非常危險的,并且是一種不得已時采用的辦法。當一個過程中出現了意料之外的錯誤時,該過程就會產生許多問題。如果忽略該錯誤,就會對用戶產生嚴重的影響,比如數據沒有保存,或者保存不正確。許多情況下,當出現代碼錯誤時,必須執行某些操作,將代碼的執行轉移到On Error GoTo語句中指定的錯誤處理程序。該語句的句法如下:
| On Error GoTo line |
請注意,line必須是指與On Error GoTo語句相同的過程中的一個語句。
在這個句法中, line有兩個意思。首先它是指出現錯誤時要轉移到的這個代碼行號。不過這個行號并不是過程中的代碼行的物理位置。請看下面這個代碼例子:
Private Sub TestErrorHandler() |
我們可能認為,被0除的錯誤會導致代碼在輸出文本line 4這個語句上繼續執行,因為這是代碼的第四個語句(不是計數注釋)。不僅這種情況不會發生,而且該代碼實際上會導致產生一個編譯錯誤,并且代碼根本不會執行。
3、用調試方式激活錯誤處理程序和取消其激活狀態
雖然我們不希望已編譯程序中的錯誤不被捕獲,但是,當程序在IDE中運行時如果出現錯誤,讓VB中止代碼的執行,這樣做常常是非常不利的。當代碼的執行中止時,會看到一條相關的出錯消息,并告訴我們出現錯誤的代碼行,這對于代碼的調試來說是大有幫助的。VB為處理代碼設計時遇到的錯誤而使用的方法取決于VB IDE的Error Trapping(捕獲錯誤)屬性。Error Trapping屬性是VB環境的一個屬性,不是某個項目的屬性。我們操作的每個項目,即使在關閉和重新啟動VB之后,均使用該設置值。若要為VB的當前會話設置Error Trapping選項,而不必為將來的會話修改默認值,請使用代碼窗口的快捷菜單上的Toggle命令(見圖2)。
圖2 從任何代碼窗口的快捷菜單中選擇Toggle命令
可以將Error Trapping屬性設置為下列值中的一個:
Break On All Errors(在所有錯誤上中止)。
Break In Class Module(在類模塊中中止)。
Break On Unhandled Errors(在未處理的錯誤上中止)。
Break On All Errors實際上可使所有錯誤處理程序均取消激活狀態。當出現一個錯誤時,無論是否激活了處理程序,代碼均在出錯的語句上進入中止方式,同時VB顯示一條出錯消息。這使我們能夠在IDE進行測試時處理意料不到的錯誤。