MasteringVFP/2/4/5

出自VFP Wiki

(修訂版本間差異)
跳轉到: 導航, 搜尋
(附註)
第111行: 第111行:
:雖然你仍然可以執行你有編譯錯誤的程式碼,但你不能這樣做,因為程序執行到此處時 Visual !FoxPro 會停止回應。
:雖然你仍然可以執行你有編譯錯誤的程式碼,但你不能這樣做,因為程序執行到此處時 Visual !FoxPro 會停止回應。
== 附註 ==
== 附註 ==
 +
*建議 Try...Catch...Finally 應與 ON ERROR DO errhand WITH ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( ) 指令配合使用,以便在程式執行時,能攔截到所有的錯誤訊息。
*就像在 Visual !FoxPro 中其他的錯誤處理程式,在 TRY...CATCH...FINALLY 異常處理程式中所發生的異常需設定 SET CONSOLE 命令為 ON。有關更多的資訊,請參閱 SET CONSOLE 命令。
*就像在 Visual !FoxPro 中其他的錯誤處理程式,在 TRY...CATCH...FINALLY 異常處理程式中所發生的異常需設定 SET CONSOLE 命令為 ON。有關更多的資訊,請參閱 SET CONSOLE 命令。
*您不能夠明確地傳輸程式執行到一個 CATCH 或 FINALLY 程式碼區塊中。
*您不能夠明確地傳輸程式執行到一個 CATCH 或 FINALLY 程式碼區塊中。
第147行: 第148行:
:#一個不被允許的命令出現在一個 TRY、CATCH 或 FINALLY 區塊中的特定區塊。有關更多的資訊,請參閱結構化錯誤處理程式 (Structured Error Handling)。
:#一個不被允許的命令出現在一個 TRY、CATCH 或 FINALLY 區塊中的特定區塊。有關更多的資訊,請參閱結構化錯誤處理程式 (Structured Error Handling)。
:#一個使用者上拋錯誤發生。
:#一個使用者上拋錯誤發生。
 +
== 範例 ==
== 範例 ==
下列範例說明如何在巢狀的 TRY...CATCH 陳述式中使用 THROW 子句以及處理 Exception 物件:
下列範例說明如何在巢狀的 TRY...CATCH 陳述式中使用 THROW 子句以及處理 Exception 物件:

在2005年2月17日 (四) 05:51所做的修訂版本

目錄

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 會停止回應。

附註

  • 建議 Try...Catch...Finally 應與 ON ERROR DO errhand WITH ERROR( ), MESSAGE( ), MESSAGE(1), PROGRAM( ), LINENO( ) 指令配合使用,以便在程式執行時,能攔截到所有的錯誤訊息。
  • 就像在 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 在以下條件下產生錯誤信息:
  1. 在 TRY...CATCH...FINALLY 結構中出現不相符或錯誤。
  2. 一個不能處理的異常發生。
  3. 一個不被允許的命令出現在一個 TRY、CATCH 或 FINALLY 區塊中的特定區塊。有關更多的資訊,請參閱結構化錯誤處理程式 (Structured Error Handling)。
  4. 一個使用者上拋錯誤發生。

範例

下列範例說明如何在巢狀的 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