2017-02-23 153 views
1

我創建了一個調用各種函數的宏,它們都返回字符串,並將結果顯示在文本框中。Excel VBA錯誤處理代碼

我開始閱讀良好的錯誤處理實踐,但有一段艱難的時間真的很瞭解它。我希望對我如何解決這個問題提出一些意見。

基本上,到目前爲止我已經實現了錯誤處理的方法是在每個函數的開頭放置一個錯誤處理程序,並對其進行設置,以便在該函數中發生錯誤時通知用戶,但繼續計算其他功能。

每一個我的功能將類似於此

Function fnGetNumbers() As String 

On Error Goto ErrorHandler 

// Code to extract numbers from text 

If NumbersInText = vbNullString Then 
    fnGetNumbers = vbNullString 
Else 
    fnGetNumbers = "The numbers in the text are: " & NumbersInText 
End If 

ErrorHandler: 
If Error <> 0 Then 
    fnGetNumbers = "An error occurred while extracting numbers from the text." 
End If 
End Function 

任何想法和/或建議,將不勝感激!

回答

1

錯誤處理(在我看來)真的要歸結爲你正在寫的宏,誰在使用它們,誰在調試它們。雖然正確和徹底的錯誤處理是最佳實踐,但如果您是唯一一個在進行調試的人,那麼您將是唯一一個需要自定義錯誤的人。這取決於你的組織,但這取決於你的需要。

話雖這麼說,在你的代碼的一些注意事項:

Function fnGetNumbers() As String 
' Instead of returning a string, you can return a boolean and pass in a 
' holder string for returning the value. This allows you to check TRUE/FALSE 
' instead of checking if a string holds an error. 

On Error Goto ErrorHandler 

// Code to extract numbers from text 

If NumbersInText = vbNullString Then 
    fnGetNumbers = vbNullString 
Else 
    fnGetNumbers = "The numbers in the text are: " & NumbersInText 
End If 

Exit Function ' Always have this before your error block. 

ErrorHandler: 
    fnGetNumbers = "An error occurred while extracting numbers from the text." 
Exit Function ' While not necessary if 
       ' it is the only error handling block, it can be good practice. 
End Function 

這也是最好返回某種值,可用於調試。返回一個簡單的字符串是沒用的,而返回一個描述錯誤類型的值更有用。

+0

請參閱BrettDJ的回答評論。感謝一堆! –

2

建議,你會不會在默認情況下這個運行的ErrorHandler部分,即無論是

  • 然後獲得一個有效的答案退出功能
  • 得到一個錯誤(下面Err.Raise 999測試)

如果我正在運行一個具有清理的長子程序(即恢復Application設置,那麼我將使ErrorHandler高於默認清理程序(以及處理髮生錯誤的事實)

所以也許這(無法抗拒輕微的調整到IF以及 - fnGetNumbers爲空默認因此無需設置)

代碼

Function fnGetNumbers() As String 

On Error GoTo ErrorHandler 

`test the error 
Err.Raise 999 

If NumbersInText <> vbNullString Then fnGetNumbers = "The numbers in the text are: " & NumbersInText 
Exit Function 

ErrorHandler: 
    fnGetNumbers = "An error occurred while extracting numbers from the text." 
End Function 
+0

真棒,太感謝你了!我討厭在這裏選擇一個評論作爲「答案」,因爲你們都非常清楚地幫助我更好地理解事情。我不知道「退出功能」這一行!現在事情變得更有意義了。 –

+0

沒問題,thx因此很快關閉並響應。很高興它是有幫助的! – brettdj

0

我會告訴你我通常做什麼。我有一個專門用於退出宏(我稱之爲exitPoint)的子例程,並且我有一個子例程控制流(我稱之爲main),在main的開始處我有一個名爲badExit的布爾值設置爲true,並且在主要結束我把它設置爲false,然後最後調用exitPoint。每個子例程或函數都有一個錯誤陷阱,它會將控制權交給ExitPoint,並使用一個字符串來指明錯誤發生在哪個例程中。然後exitPoint運行一系列清理錯誤處理代碼,具體取決於badExit是true還是false。

基本上這個想法是我會提供支持,如果它是一個宏,我將它交給別人再也看不到它,我會在那裏放置更多的防禦性編碼和有用的錯誤信息 - 你可以測試爲一個錯誤號碼,並給出一個特定的消息,例如。

因此,像這樣(這是我剪了大量的代碼出的實際宏只是爲了說明):

Option Explicit 
Option Private Module 

... 

Private mbBadExit  As Boolean 
Private msMacroWbName As String 
Private msMacroWbPath As String 
Private miSaveFormat As String 
Private miSheetsInNewWb As String 
Private mcolWorkbooks As New Collection 
Private mwbkNew   As Workbook 

... 

Sub Main() 
' --------------------------------------------------------------------- 
' Control procedure 
' --------------------------------------------------------------------- 

    Debug.Print "Main Start " & Time 

    'set exit state 
    mbBadExit = True 

    'set macro document name and path 
    msMacroWbName = ThisWorkbook.Name 
    msMacroWbPath = ThisWorkbook.Path 

    miSaveFormat = Application.DefaultSaveFormat 
    miSheetsInNewWb = Application.SheetsInNewWorkbook 

    'disable some default application behaviours for macro effeciency 
    With Application 
     .Calculation = xlCalculationManual 
     .ScreenUpdating = False 
     .DisplayAlerts = False 
     .EnableEvents = False 
     .DisplayStatusBar = False 
     .DefaultSaveFormat = xlOpenXMLWorkbook 'for excel 2007 compatability 
     .SheetsInNewWorkbook = 3 
    End With 

    Debug.Print "AddNew Start " & Time 
    AddNew    'creates new workbook which the rest of the macro works with 
    Debug.Print "Import Start " & Time 
    Import    'import bobj CP_Import file and scalepoint data 
    Debug.Print "Transform Start " & Time 
    Transform   'various data munging to final state 
    mbBadExit = False 'set exit state for clean exit 
    Debug.Print "ExitPoint Start " & Time 
    ExitPoint   'single exit point 

End Sub 

Private Sub ExitPoint(Optional ByVal sError As String) 
' --------------------------------------------------------------------- 
' Single exit point for macro, handles errors and clean up 
' --------------------------------------------------------------------- 

    Dim mwbk As Workbook 

    'return application behaviour to normal 
    On Error GoTo 0 
    With Application 
     .DisplayAlerts = True 
     .Calculation = xlCalculationAutomatic 
     .ScreenUpdating = True 
     .EnableEvents = True 
     .DisplayStatusBar = True 
     .DefaultSaveFormat = miSaveFormat 
     .SheetsInNewWorkbook = miSheetsInNewWb 
    End With 

    'handle good or bad exit 
    If mbBadExit = False Then 'no problem 
     MsgBox "Process complete" 
     'close this workbook, leaving result workbook open 
     Application.DisplayAlerts = False 
     Set mcolWorkbooks = Nothing 'destroy collection object 
     Workbooks(msMacroWbName).Close 'close macro wbk 
     Application.DisplayAlerts = True 
    Else 'an error occured 
     'show user error details 
     MsgBox prompt:="Macro process has ended prematurely. Contact ... for support." _ 
      & IIf(sError <> vbNullString, vbCrLf & sError, vbNullString) & vbCrLf _ 
      & Err.Description, Title:="Error " & IIf(Err.Number <> 0, Err.Number, vbNullString) 
      On Error Resume Next 
     'clean up open workbooks 
     For Each mwbk In mcolWorkbooks 
      mwbk.Close 
     Next 
    End If 

    Debug.Print "Finish " & Time 

    End 

End Sub 

Private Sub AddNew() 
' --------------------------------------------------------------------- 
' Creates new workbook which is the base workbook for 
' The rest of the macro 
' --------------------------------------------------------------------- 

    On Error GoTo errTrap 

    Set mwbkNew = Workbooks.Add 
    mcolWorkbooks.Add mwbkNew 
    With mwbkNew 
     .Title = "CP HR Import" 
     .Subject = "CP HR Import" 
    End With 

    Exit Sub 

errTrap: 

    ExitPoint ("Error in AddNew sub routine") 'pass control to error handling exitpoint sub 

End Sub 

Private Sub Import() 
' --------------------------------------------------------------------- 
' Connect to source file (xlsx) with ADO, pull data into a recordset 
' with SQL, then pull data to the workbook from the recordset to a 
' querytable. Kill connection etc.. 
' --------------------------------------------------------------------- 

    On Error GoTo errTrap 

    ...Code here... 


    Exit Sub 

errTrap: 

    ExitPoint ("Error in Import sub routine") 'pass control to error handling exitpoint sub 

End Sub 

Sub Transform() 
' --------------------------------------------------------------------- 
' Looks for records with an increment date and inserts a new record 
' showing the new scalepoint from the increment date with the new 
' salary 
' --------------------------------------------------------------------- 

    On Error GoTo errTrap 

    ...code here... 

    Exit Sub 

errTrap: 

    ExitPoint ("Error in Transform sub routine") 'pass control to error handling exitpoint sub 

End Sub 

Sub ColumnsToText(rngColumns As Range) 
' --------------------------------------------------------------------- 
' Takes a column as a range and converts to text. UK date safe but 
' not robust, use with care. 
' --------------------------------------------------------------------- 

    Dim avDates  As Variant 

    avDates = rngColumns.Value 
    With rngColumns 
     .NumberFormat = "@" 
     .FormulaLocal = avDates 
    End With 

    Exit Sub 

errTrap: 

    ExitPoint ("Error in ColumnsToText sub routine") 'pass control to error handling exitpoint sub 

End Sub