我有一个功能与此类似的模块:
主模块
Sub Test()
On Error Resume Next
Dim O1 As New Class1
O1.DoSomething
On Error GoTo 0
End Sub
还有一些与此类似的课程:
1班
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
VBA 菜单“工具”>“选项”>“常规”选项卡中有一个错误捕获选项:
如果我将错误捕获设置为
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
1班
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
中所示。
正如您所注意到的,您无法仅通过调整 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