【问题标题】:Debugging errors in VBA classes in Excel在 Excel 中调试 VBA 类中的错误
【发布时间】:2016-11-03 02:53:57
【问题描述】:

我有一个功能类似于此的模块:

主模块

Sub Test()
  On Error Resume Next
  Dim O1 As New Class1
  O1.DoSomething
  On Error GoTo 0
End Sub

还有一些类似的类:

Class1

Sub DoSomething()
  FindStuff

  'create similar objects who perform similar operations and raise similar errors
  Dim O2 As New Class2
  O2.DoSomething
End Sub

Function FindStuff() As Stuff
  'scan the WorkBook, the file system, etc. and organize the members of the object
  If CorruptedFileSystem Then Err.Raise 514, "File system corrupted"
  If CorruptedWorkBook Then Err.Raise 515, "WorkBook corrupted"
  If Found Then Set FindStuff = FoundStuff
End Function

如果我将错误捕获设置为Break in Class Module,那么On Error Resume Next 将被忽略,每个Err.Raise 都会停止类内的执行。

如果我将错误捕获设置为Break on Unhandled Errors,那么Err.Raise 将在主模块调用时停止执行,而不是在类内部。

所以在一种情况下我无法执行带有已处理错误的代码,在另一种情况下我无法调试未处理的错误。

当项目增长并且主模块创建一个对象,该对象打开一个创建更多对象的表单(这是另一个对象)时,问题变得难以管理。一些方法处理它们自己的错误,而另一些方法旨在中止并引发由调用者管理的错误。

有没有办法处理和调试类中的错误?

编辑

显然我的问题不够清楚。我更改了标题,我将尝试一个更清晰的示例。

模块1

Sub Test1()
  Dim O As New Class1
  O.UnhandledCall
End Sub

Sub Test2()
  On Error Resume Next
  Debug.Print 1 / 0
  Dim O As New Class1
  O.HandledCall
  On Error GoTo 0
End Sub

Class1

Sub UnhandledCall()
  Debug.Print 2 / 0
End Sub

Sub HandledCall()
  Debug.Print 3 / 0
End Sub

测试1

设置Error Trapping = Break on Unhandled Errors 并执行Test1。调试器不会在未处理的错误2 / 0 处停止。相反,它将停在O.UnhandledCall,因此无法知道是哪一行导致了错误、局部变量值是什么、堆栈等。

测试2

设置Error Trapping = Break in Class Module 并执行Test2。调试器不会停在1 / 0,很好,因为错误已被处理。但是即使在调用函数内部处理了错误,它也会在类内部的3 / 0处停止,与1 / 0处于同一级别。

悲伤的总结

所以第一个设置我看不到哪里出现错误,第二个设置我不能运行一个干净地处理错误的宏。

这显然是一个过于简单的例子。我现在处理的真实世界案例是一个创建数十个对象的表单,一些对象检查一些文本文件,其他对象通过 COM 在 CAD 上打开图形,其他对象与数据库通信等。如果有任何一个条件不一致我想中止表单打开。

创建对象时,它们会执行数千行代码,其中包含数百个托管错误。当他们在文件、绘图或数据库中发现无法管理的内容时,他们会将错误处理推迟给调用者,将堆栈向上爬到应该无法打开的表单和应该检测到错误并执行的调用者关于它。

我希望调试器在托管错误中顺利运行,并在违规行出现非托管错误时停止。相反,调试器在模块中按预期工作,但在类中它要么停止所有错误,要么永远不会停止,无论它们是否被管理。

例如,如果我设置Error Trapping = Break in Class Module,所有托管错误都会像Test2 一样中断执行,并且我的调试会话将永远不会结束。

如果我设置了Error Trapping = Break on Unhandled Errors,那么我永远不会知道是什么触发了错误,因为调试器会爬过所有类直到第一个对象并告诉我这是导致错误的行,如Test1 .

【问题讨论】:

  • 你为什么会有如此详尽的错误处理被如此广泛的On Error Resume Next括起来?
  • 我不明白你的问题
  • On Error Resume Next 抑制错误并让代码愉快地继续运行,违背了结构化错误处理的目的。您的顶级调用者应该有自己的 On Error GoTo CleanFail 或其他东西,以处理在调用堆栈中冒泡到该点的任何错误。
  • 我同意你的观点,但我仍然不明白你的评论。你说的和我说的有什么区别?您是在谈论CleanFail0 之间的区别吗?它们只是做同一件事的两种方法,不会改变我的问题的重点。我本可以添加一些关于如何管理故障的详细信息,但这与调试器处理已处理或未处理错误的行为方式无关。
  • 有两个不同的评论者。考虑像@​​Doug Glancy 一样通知您已回复的人。除此之外,您还坚持自己目前的思维方式,祝您好运!

标签: excel vba debugging error-handling


【解决方案1】:

正如您所注意到的,仅通过调整 IDE/调试器设置,您无法冒泡类模块中引发的运行时错误现场调试。

还有另一种方法。定义一个项目范围的条件编译值,比如DEBUG_MODE

在您的类模块的错误处理程序中,使用条件编译逻辑进行编程中断:

Public Function FetchResults(ByVal filter As String) As Collection
    On Error GoTo CleanFail

    Dim results As Collection
    Set results = this.Repository.Where(filter)

CleanExit:
    Set FetchResults = results
    Exit Function

CleanFail:
#If DEBUG_MODE = 1 Then
    Stop
#Else
    Err.Raise Err.Number 'rethrows with same source and description
#End If
    Set results = Nothing
    Resume CleanExit
End Sub

如果您不介意 VBE 出现在您的困惑用户身上,那么您也可以使用 Debug.Assert 语句在不满足条件时中断执行:

Public Function FetchResults(ByVal filter As String) As Collection
    On Error GoTo CleanFail

    Dim results As Collection
    Set results = this.Repository.Where(filter)

CleanExit:
    Set FetchResults = results
    Exit Function

CleanFail:
    Debug.Assert Err.Number <> 0 ' will definitely break here
    Set results = Nothing
    Resume CleanExit
End Sub

【讨论】:

  • 对不起,我的问题不是关于如何编写管理错误的代码,而是关于调试器如何管理错误处理。我编辑了问题的标题并添加了更详细的示例。显然,如果以不同的方式编写代码有帮助,我会将其作为答案
  • 没错。您知道导致错误的原因,因为您处理它们的方式将该信息传递给处理它的错误处理程序。我不知道该怎么说,对不起。
  • 如果您要在两个字符串中携带信息,而不是像我在简化示例中那样,这是一个小的改进。我希望调试器在错误处停止并探索所有局部变量的值,能够尝试一些快速修复,更改下一条语句并进行实验。我想对类做你在任何正常调试会话期间使用模块时所做的事情(这只是另一种类,但它们在调试器中的行为符合预期)
  • 标准模块与类模块完全没有关系。正如 Doug 上面所说,除此之外,您还非常坚持自己目前的思维方式,祝您好运!
  • 再说一遍:你在说什么新的思维方式?我问了一个关于调试器的问题,我在 cmets 中收到了一个问题,还有一个我没有问的问题的答案。我知道我最初的问题不清楚,但我认为现在很清楚我在问什么。如果您已经回答,请告诉我答案在哪里,因为我没有看到它。如果不是,请在不解释原因的情况下回答或停止咄咄逼人
猜你喜欢
  • 2011-12-19
  • 2021-03-15
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-18
相关资源
最近更新 更多