VBA错误“冒泡”

时间:2009-09-13 20:33:44

标签: vba excel-vba excel

我没有太多关于它的内容,但是下面链接的作者建议我不要使用“冒泡”来集中VBA中的错误处理。

Excel Programming Weekend Crash Course via Google Books

但我不确定他为什么这么推荐,而且他没有真正解释。

有人可以告诉我为什么我应该在每个程序中使用错误处理而不是使用“冒泡”?或者至少,你知道作者为什么不这么说?

感谢。

5 个答案:

答案 0 :(得分:13)

对第一个问题的简短回答是“你不应该在每个程序中放置一个错误处理程序”。

要说“每个程序必须有一个错误处理程序”,一般都是可怕的建议。其他地方已经讨论了VBA错误处理的缺陷。但从概念上讲,它与其他语言中更标准的异常处理形式并没有什么不同。这些语言的大多数最佳实践都适用。您应该在处理它们的最低级别处理错误。有时这是在发生错误的过程中,很多时候都没有。

例如,从工作表调用的VBA UDF当然应该有一个EH,确保将Excel错误值返回给调用单元,而不是将用户放入代码编辑器中并显示错误消息。但是,从UDF调用的代码可能需要也可能不需要。实际上,当发生错误时,内部例程通常可以做的最有意义的事情就是让它传递到堆栈上,这样它就可以到达知道如何处理它的代码。这实际上取决于例程。

你的第二个问题的答案是作者似乎不太了解异常处理。他承认错误处理是特定于上下文的,但似乎建议每个过程都应在本地“在此纠正问题并恢复执行”和“终止程序”之间做出决定。他遗漏了通常正确的选项,即“在当地清理并将问题解决到楼上”。因此,无需在本地清理的例程应该让错误“冒泡”。

答案 1 :(得分:1)

我的2美分: 您应该在所有公共过程和事件上放置错误处理程序。这意味着调用堆栈底部的过程将始终具有错误处理程序。然后在其他过程中添加错误处理程序,因为它是有意义的。如果在没有错误处理程序的过程中发生错误,它将“冒泡”到顶级错误处理程序,以专业方式记录/显示它。 您可能希望将错误处理程序添加到私有(较低级别)过程的方案是: 代码需要快速。您有一个可以避免的罕见情况,但会强制您在循环内执行昂贵的逻辑测试(或者更糟糕的是嵌套循环)。 您可以在错误处理程序中执行逻辑测试,如果说“罕见”则进行更正并恢复。由于条件很少,您将看到大多数条件下的性能提升。如果错误处理程序无法弄清楚并纠正问题,那么重新引发错误以将其冒泡到堆栈上。

显然这只是一种情况。

答案 2 :(得分:0)

我在他的解释中至少看到一个原因:因为这样做会使你免于恢复(下一个)的好处。
另外,您不会知道错误发生在哪个模块中。

答案 3 :(得分:0)

我不确定VBA的默认错误处理是什么,但由于它的Visual Basic for Applications,以及那些应用程序包含excel和word之类的东西,我假设只会出现一个对话框,这对于用户。

我认为作者被代码所困,因为他现在建议所有程序来处理错误。

完整的答案是你必须了解可能发生的每一个错误,并有代码来处理它,是否尽可能低(你可能不知道该做什么),或者高尽可能少(这意味着编写错误处理代码的工作量减少,但不知道错误发生的原因),或者战略性地(在正确的位置,您应该能够从最常见的错误中恢复)或者只是在任何地方(可能是只是开发工作太多了。)

答案 4 :(得分:-1)

最好不要使用错误处理的“冒泡”部分,因为应该处理错误&如果知道该怎么做,如果发生这样的错误 - 对程序更好地了解而不是调用程序

Sub test()
  On Error GoTo e
  Dim c As Integer
  Dim d As Integer
  c = add(5, 0)
  d = divideWhichManagedItsOwnErrorHandling(5, 0)
  d = divide(5, 0)

  Exit Sub

e:
  MsgBox "error occurred somewhere for which I don't know what to do: " + Err.Description
End Sub

Function add(a As Integer, b As Integer) As Integer
   add = a + b
End Function

Function divide(a As Integer, b As Integer) As Integer
   divide = a / b 'if error occurs, it will "bubble-up" to the caller.
End Function

Function divideWhichManagedItsOwnErrorHandling(a As Integer, b As Integer) As Integer
  On Error Resume Next
  Dim result As Integer
  result = a / b
  If Err.Number = 11 Then 'if divide by zero occurred, user must have passed 0 for b
    result = 0 ' return 0 if the divide by zero occurs. 
  End If
  divideWhichManagedItsOwnErrorHandling = result
End Function