MasteringVFP/2/4/5
出自VFP Wiki
目錄 |
TRY...CATCH...FINALLY 命令 (8.0 新增)
用途
- 提供一個結構來處理執行一個程式碼區塊時可能發生的錯誤和異常。
語法
- TRY
- [ tryCommands ]
- [ CATCH [ TO !VarName ] [ WHEN lExpression ]
- [ catchCommands ] ]
- [ EXIT ]
- [ THROW eUserExpression ]
- [ FINALLY
- [ finallyCommands ] ]
- ENDTRY
參數
TRY
- 指出 TRY...CATCH...FINALLY 結構的開始。
tryCommands
- 指定可能發生錯誤的陳述式。
- 如果發生錯誤,Visual !FoxPro 儲存一個 Exception 物件參照至 !VarName 記憶體變數中。程式執行直接到 CATCH 陳述式。
- 如果沒有發生錯誤,程式執行到 FINALLY 陳述式。
CATCH
- 指明處理錯誤的 CATCH 區塊的開始。
- 若 CATCH WHEN 求值結果為 .T. (真)時,可以指定一個不帶參數的 CATCH 陳述式。
- 只有當一個錯誤在那個方法程序的 TRY 區塊中發生以及在方法程序中的程式碼導致例外的時候,CATCH 敘述式會被呼叫。
- 如果另外的方法程序是從此 TRY 區塊裡面呼叫而導致一個錯誤時,Error 事件對那個方法程序來處理此錯誤。
- 這行為發生是因為另一個方法程序可以直接或從一個不包含 TRY...CATCH...FINALLY 結構之不同的方法程序來呼叫。
- 下列範例舉例說明這行為:
- x = NEWOBJECT("myClass")
- x.myMethod()
- DEFINE CLASS myClass AS Session OLEPUBLIC
- PROCEDURE myMethod
- myMethod3() && Error 事件處理錯誤。
- TRY
- THIS.myMethod2()
- myMethod3() && CATCH 處理這個錯誤。
- CATCH TO oErr
- ? "Catch:",oErr.!ErrorNo
- FINALLY
- ENDTRY
- ENDPROC
- PROCEDURE myMethod2
- x = y && y 變數不存在。
- && Error 事件處理這個錯誤。
- ENDPROC
- PROCEDURE Error(nError, cMethod, nLine)
- ? "Error:",nError
- ENDPROC
- ENDDEFINE
- PROCEDURE myMethod3
- x = y
- ENDPROC
TO !VarName
- 指定一個用於儲存 Exception 物件參照至可選用的記憶體變數,它在 TRY 區塊中發生錯誤時會自動建立。
- !VarName 只能是一個簡單的記憶體變數,不能是物件屬性參照。
- 可以在 TRY...CATCH...FINALLY 結構中明確地設定 !VarName 為任何值。只要另一個 CATCH 敘述式沒有被執行(重設定 !VarName 為 NULL),該值不會改變。
- !VarName 可以為 local(區域)、public(公共) 或 private(私有) 作用域,這取決於變數先前是如何定義的。
- 如果 !VarName 在之前沒有定義,那麼它是 private。
- 建立的 Exception 物件與 !VarName 具有相同的作用域。當 !VarName 超出作用域、被釋放或重設定時,Exception 物件也被釋放。
- 當一個 CATCH TO !VarName 子句執行時,雖然 !VarName 保留它的作用域,Visual !FoxPro 總是設定 !VarName 記憶體變數為一個新的 Exception 物件而不管它早先的設定。因此,!VarName 的內容總是被覆蓋而不管它先前的參照。
- 如果存在一個 WHEN 子句,而且它的求值為假 (.F.) 時,Visual !FoxPro 釋放 Exception 物件並重設定 !VarName 為 NULL。
- 你可以用 VARTYPE() 函數測試是否 !VarName 被設定為一個類型或是 NULL。
WHEN lExpression
- 指定一個可選用的在程式遇到 CATCH 敘述式是被求值的表達式。為了使相應的 catchCommands 執行,該表達式的值必須為真 (.T.)。
- lExpression 參數可以包含一個 參照到 !VarName 的 Exception 物件,這樣你就可以檢查錯誤結果並處理它。
catchCommands
- 指定當程式遇到相應的 CATCH 敘述式時要執行的敘述式。
THROW [ eUserExpression ]
- 建立一個被 CATCH 陳述式接收的新 Exception 物件。
- eUserExpression 參數指定一個任意類型的運算式並設定 Exception 物件的 !UserValue 屬性。
- 通常在一個 CATCH 區塊中用一個 THROW 子句來增強對一個更高級的錯誤處理程式的錯誤或異常。
- 你可以傳遞一個任意類型的物件,因為 Exception 的 !UserValue 只儲存物件參照。
- 當你使用有 eUserExpression 參數的 THROW 子句時,Visual !FoxPro 設定 Exception 物件的 !ErrorNo 屬性值為 2071,相應於錯誤:User Thrown Error (錯誤 2071)。
- 如果您省略 eUserExpression 且 Exception 物件存在,Visual !FoxPro 增強原始的 Exception 物件。
- 如果 Exception 物件不存在,Visual !FoxPro 拋出一個新的、!ErrorNo 屬性值為 2071 的 Exception 物件。
- 注意
- 你應該為 eUserExpression 傳遞一個值,它設定 Exception 物件的 !UserValue 屬性,因為它允許你鏈接多個 Exception 物件。
- 關於鏈接 Exception 物件的相關資訊,請參見範例。
- 如果你不包括 eUserExpression,而且 THROW 子句增強對一個外部的 TRY...CATCH 區塊之 Exception 物件,相同的 Exception 物件由外部的 TRY...CATCH 區塊捕捉。
- 當使用在一個結構化異常處理程式中,由 ERROR()、MESSAGE( ) 和 AERROR( ) 函數所傳來的值總是不可靠的,如此你應該使用 Exception 物件來替代。
- 你能在一個 TRY...CATCH...FINALLY 結構中呼叫來自任何的程式碼區塊。然而,你能任意在一個存在捕捉異常的程式碼之錯誤處理程式中使用 THROW。
- 你不能夠從命令視窗來呼叫 THROW。
- 警告
- 呼叫在 TRY...CATCH...FINALLY 結構外的 THROW 命令以及沒有一個適當的錯誤處理程式會導致你的程式結束。
- 如果當 THROW 是從一個 CATCH 或 FINALLY 區塊所呼叫時,一個外部的 TRY...CATCH 陳述式是有效的,Visual !FoxPro 在 CATCH TO 子句指定 !VarName 為對拋出的異常所產生的 Exception 物件之物件參照。
- 如果外部的 TRY...CATCH 陳述式是無效的,Visual !FoxPro 逐步上移異常到一個可能存在的 ON ERROR 或 ERROR 事件;否則,Visual !FoxPro 呼叫它的系統錯誤處理程式。
- 注意
- 執行時期應用程式應該正確地封裝 THROW 陳述式到一個外部的 TRY...CATCH...FINALLY 結構中。
- 如果你想重新拋出原始的由 CATCH TO !VarName 子句所捕捉到的異常,你可以呼叫 THROW !VarName 來重新拋出異常。
- 注意
- 重新拋出原始的異常產生另一個新的 Exception 物件,在外部的 CATCH 陳述式中,有一個 !UserValue 屬性包含有原始異常的物件參照。
- Visual !FoxPro 忽略任何出現在 CATCH WHEN eExpression 子句中的 THROW 陳述式。
- 如果 THROW 在評估一個運算式遇到一個錯誤時,Visual !FoxPro 以平常的方式上移錯誤。
EXIT
- 包括在一個 TRY、CATCH 或 FINALLY 區塊中來直接退出代碼區塊。
- 如果 EXIT 出現在 TRY 或 CATCH 區塊中且 FINALLY 陳述式存在,程式再繼續執行 FINALLY 陳述式。
- 如果 EXIT 出現在 FINALLY 區塊中或如果 FINALLY 不存在,程式再繼續執行到下一個 ENDTRY 陳述式。
FINALLY
- 指出 FINALLY 區塊的開始,在該區塊中你可以清除任何由 TRY 區塊分配的資源,除非使用了 CANCEL 和 QUIT 命令否則總是會執行該區塊中的程式碼。
- 有關更多使用於 TRY...CATCH...FINALLY 結構中之命令的資訊,請參閱英文版的 Structured Error Handling (結構化錯誤處理)章節。
finallyCommands
- 指定要在 FINALLY 區塊中執行的陳述式,這些陳述式在 TRY 區塊中沒有發現錯誤或是執行了 CATCH 中的陳述式後執行。
ENDTRY
- 指出 TRY...CATCH...FINALLY 結構的結束。
- 每個 TRY...CATCH...FINALLY 結構必須以 ENDTRY 關鍵字結束。
- 與其它 Visual !FoxPro 控制項敘述式一樣,可以在前面加 && 符號來加入註釋到 ENDTRY 後面。
- 如果在 TRY...CATCH...FINALLY 結構的尾端中沒有包括 ENDTRY 敘述式,當你編譯你的程式碼時 Visual !FoxPro 產生一個錯誤。
- 雖然你仍然可以執行你有編譯錯誤的程式碼,但你不能這樣做,因為程序執行到此處時 Visual !FoxPro 會停止回應。
附註
- 就像在 Visual !FoxPro 中其他的錯誤處理程式,在 TRY...CATCH...FINALLY 異常處理程式中所發生的異常需設定 SET CONSOLE 命令為 ON。有關更多的資訊,請參閱 SET CONSOLE 命令。
- 您不能夠明確地傳輸程式執行到一個 CATCH 或 FINALLY 程式碼區塊中。
- Visual !FoxPro 決定變數的範圍是在一個程序化上而不是以區塊為基準。
- 也就是說,在 TRY 區塊中宣告的變數在同一個 TRY...CATCH...FINALLY 結構的 FINALLY 區塊中也是看得見的。
- 但是,在一個巢狀的結構中,在 TRY、CATCH 或 FINALLY 區塊中所宣告的變數是屬於區域範圍。
- 您不應在 TRY 區塊內部初始化變數或設定條件代碼,因為不能保證代碼會執行。
- 如果一個錯誤出現在 TRY 區塊代碼中的特定列,所有在 TRY 區塊中後續的代碼將不會執行。
- 任何發生在一個物件的 ERROR 事件中的錯誤是由該物件來處理的,而不是上移到 ON ERROR 常式或 TRY...CATCH...FINALLY 處理程式。
- 然而,您可以在 ERROR 事件中使用一個 TRY...CATCH...FINALLY 結構來找出來自一個 ERROR 事件的錯誤。有關更多的資訊,請參閱 ERROR 事件。
- 在 CATCH 區塊中用 COMRETURNERROR() 函數結束所有進一步的處理並直接傳回程式控制到元件物件模型 (Component Object Model;COM) 用戶端。
- 因此,如果你有一個 FINALLY 區塊,它不會執行。有關更多的資訊,請參閱 COMRETURNERROR( ) 函數。
- 避免在 TRY...CATCH...FINALLY 結構中使用 SET TEXTMERGE TO MEMVAR 命令,因為如果在陳述式中發生錯誤記憶體變數將變將會被遺失。
- 可以在你的 TRY...CATCH...FINALLY 程式碼中用 SYS(2410) - 錯誤處理程式函數來檢測動作過程,例如:用一個 DO CASE 結構,藉由處理程式類型來處理異常。有關更多的資訊,請參閱 SYS(2410) - 錯誤處理程式。
- 如果結構封裝正確,您可以使用 TRY...CATCH...FINALLY 和像 ON KEY LABEL 這樣的命令來處理出現在功能表和計時器事件中的錯誤。
- 下面範例說明 READ EVENTS 命令如何在一個 TRY...CATCH...FINALLY 結構中保持程式控制,因此可以捕捉功能表事件。
- 錯誤捕捉是由 TRY...CATCH...FINALLY 在呼叫堆疊的位置控制的。
TRY DO myMenu.mpr DO FORM myForm myForm.!AddObject("tm1","mytimer") READ EVENTS CATCH TO oException IF oException.!ErrorNo = 1 ENDIF FINALLY CLEAR EVENTS ENDTRY
- 有關更多的資訊,請參閱 READ EVENTS 命令和 ON KEY LABEL 命令。
- Visual !FoxPro 僅在單一的程式碼區塊中支援 Set Next Statement 除錯功能。例如:當執行 TRY 區塊中的程式碼時,你只能用 Set Next Statement 到另一 TRY 區塊中的另一行。你不能夠跳到在 CATCH 或 FINALLY 區塊中別的行。有關更多的資訊,請參閱除錯程式鍵盤快速鍵和功能表 (Debugger Keyboard Shortcuts and Menus)。
- Visual !FoxPro 在以下條件下產生錯誤信息:
- 在 TRY...CATCH...FINALLY 結構中出現不相符或錯誤。
- 一個不能處理的異常發生。
- 一個不被允許的命令出現在一個 TRY、CATCH 或 FINALLY 區塊中的特定區塊。有關更多的資訊,請參閱結構化錯誤處理程式 (Structured Error Handling)。
- 一個使用者上拋錯誤發生。
範例
下列範例說明如何在巢狀的 TRY...CATCH 陳述式中使用 THROW 子句以及處理 Exception 物件:
LOCAL x ,y ,result && 整數 LOCAL oErr , oErr1 && Exception 物件 TRY x = 1 TRY USE nothing GO TOP y = nothing.col1 CATCH TO oErr oErr.!UserValue = "巢狀的 CATCH 訊息:不能處理" ?[:巢狀的 Catch!(無法處理:上拋至 oErr 物件上) ] ?[ 內部 Exception 物件:] ?[ 錯誤:] + STR(oErr.!ErrorNo) ?[ 列數:] + STR(oErr.!LineNo) ?[ 訊息:] + oErr.Message ?[ 程序:] + oErr.Procedure ?[ 詳細資料:] + oErr.Details ?[ 堆疊層級:] + STR(oErr.!StackLevel) ?[ 列內容:] + oErr.!LineContents ?[ !UserValue:] + oErr.!UserValue THROW oErr FINALLY ?[:巢狀的 FINALLY 被執行] IF USED("nothing") USE IN nothing ENDIF ENDTRY result = x - y CATCH TO oErr1 ?[:外部 CATCH!] ?[ 外部 Exception 物件:] ?[ 錯誤:] + STR(oErr1.!ErrorNo) ?[ 列數:] + STR(oErr1.!LineNo) ?[ 訊息:] + oErr1.Message ?[ 程序:] + oErr1.Procedure ?[ 詳細資料:] + oErr1.Details ?[ 堆疊層級:] + STR(oErr1.!StackLevel) ?[ 列內容:] + oErr1.!LineContents ?[ ->!UserValue becomes inner exception THROWn from nested TRY/CATCH ] ?[ 錯誤:] + STR(oErr1.!UserValue.!ErrorNo) ?[ 訊息:] + oErr1.!UserValue.Message ?[ 程序:] + oErr1.!UserValue.Procedure ?[ 詳細資料:] + oErr1.!UserValue.Details ?[ 堆疊層級:] + STR(oErr1.!UserValue.!StackLevel) ?[ 列內容:] + oErr1.!UserValue.!LineContents ?[ !UserValue:] + oErr1.!UserValue.!UserValue result = 0 FINALLY ?[:FINALLY 陳述式被執行] ENDTRY RETURN result
下列範例顯示如何去連結 Exception 物件:
TRY TRY x = y && y 變數不存在造成一個錯誤。 CATCH TO oException2 THROW CREATEOBJECT("myException") ENDTRY CATCH TO oException1 ENDTRY ? 2, oException2.!ErrorNo, oException2.!UserValue ? 1, oException1.!ErrorNo, oException1.!UserValue.!UserValue DEFINE CLASS myException AS Exception !UserValue = "我自定的錯誤處理程式" PROCEDURE Init STRTOFILE("一個錯誤發生在:" + TRANSFORM(DATETIME()) + CHR(13),"c:\errs.log",.T.) ENDPROC ENDDEFINE