gpt4 book ai didi

vba - On Error Goto 在 EventHandler subs 中不起作用

转载 作者:行者123 更新时间:2023-12-04 14:15:36 25 4
gpt4 key购买 nike

让我们假设这段代码:

模块1:

Sub main()

Dim cl As New Class2
On Error GoTo errorhandler1
cl.DoWork
On Error GoTo 0
Exit Sub

errorhandler1:
MsgBox (Err.Description)

End Sub

第一类:
Event MyEvent()

Public Sub DoWork()
RaiseEvent MyEvent
End Sub

类2:
Private WithEvents cl As Class1

Private Sub cl_MyEvent()
Call Err.Raise(123, , "ErrorInClass")
End Sub

Private Sub Class_Initialize()
Set cl = New Class1
End Sub

Public Sub DoWork()
cl.DoWork
End Sub

我希望启动 errorhandler1 并显示带有 err.Description 的 MsgBox。
但它却给我抛出了运行时错误。

我必须做什么来处理 EventHandlers 例程中的错误?

最佳答案

这让我很生气——你可以在这个简单的 C# 代码中看到:

try
{
SomeEvent?.Invoke(this, EventArgs.Empty);
}
catch
{
// break here
}

如果 SomeEvent 的任何处理程序抛出异常,AFAIK 中的断点 catch block 会被击中 - 我期待 VBA 做同样的事情......但它没有。

通过中断事件处理程序,然后检查调用堆栈,您可以看到在事件源与 RaiseEvent 之间存在一些问题。调用和事件处理程序:

"Non-Basic Code" between the event source and the event handler

我认为 [<Non-Basic code>]这将是 VBA 运行时本身,将事件分派(dispatch)到正在监听该特定事件源实例上的事件的任何对象:而这种“中间人”很可能是为什么运行时错误不会冒泡的原因:运行时可能会保护自己并在此处抛出错误,无论父堆栈帧是否具有 On Error陈述。

您可以在该屏幕截图中看到我的解决方法的提示 - 添加一个新的类模块,将其命名为 ErrorInfo ,并给它一些有用的成员:
Option Explicit
Private Type TErrorInfo
Number As Long
Description As String
Source As String
End Type
Private this As TErrorInfo

Public Property Get Number() As Long
Number = this.Number
End Property

Public Property Get Description() As String
Description = this.Description
End Property

Public Property Get Source() As String
Source = this.Source
End Property

Public Property Get HasError() As Boolean
HasError = this.Number <> 0
End Property

Public Property Get Self() As ErrorInfo
Set Self = Me
End Property

Public Sub SetErrInfo(ByVal e As ErrObject)
With e
this.Number = .Number
this.Description = .Description
this.Source = .Source
End With
End Sub

现在,每当您定义一个事件时,请为其添加一个参数:
Public Event Something(ByVal e As ErrorInfo)

当您引发该事件时,提供实例、处理错误、检查您的 ErrorInfo对象,调用 Err.Raise因此,您可以正常处理该错误,在您想要处理事件处理程序错误的事件调用范围内:
Public Sub DoSomething()
On Error GoTo CleanFail
With New ErrorInfo
RaiseEvent Something(.Self)
If .HasError Then Err.Raise .Number, .Source, .Description
End With
Exit Sub
CleanFail:
MsgBox Err.Description, vbExclamation
End sub

事件处理程序代码只需要处理它的错误(处理程序中的任何运行时错误基本上都是未处理的),并在 ErrInfo 中设置错误状态。范围:
Private Sub foo_Something(ByVal e As ErrorInfo)
On Error GoTo CleanFail
Err.Raise 5
Exit Sub
CleanFail:
e.SetErrInfo Err
End Sub

还有宾果游戏,现在您可以在事件源处干净地处理事件处理程序中引发的错误,而无需涉及全局变量或 losing the actual error information (在我的情况下,一些第 3 方 API 中抛出的错误)到一些无用的(但在大多数情况下可以说是“足够好”)“哎呀,没用”消息。

重要警告

Cancel 的情况一样事件,如果一个事件有多个处理程序,那么返回到事件调用站点的状态是未定义的 - 如果只有一个处理程序抛出错误,并且非抛出处理程序不会篡改 ErrorInfo参数,那么理论上调用站点会得到一个错误。当两个或多个处理程序抛出错误时,“乐趣”就开始了。

在这种情况下,处理程序需要验证 ErrorInfo 的状态。是在他们修改它之前。

或者,另一种解决方案可能是使 ErrorInfo类封装了一组错误信息,并可能将索引器添加到 Property Get成员 - 或您可以考虑的任何其他机制,以“汇总错误”。哎呀,您甚至可以封装 ErrorInfo 的集合 AggregateErrorInfo 中的实例集合类,并让您的“多听众事件”在其签名中使用它。

大多数时候你只需要一个处理程序,所以这不是问题。

关于vba - On Error Goto 在 EventHandler subs 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30935147/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com