gpt4 book ai didi

vba - VBA 中的哨兵对象

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

我在网络和我自己的项目中随处可见具有以下模式的代码:

Sub Func()
Application.EnableEvents = False
' some code
Application.EnableEvents = True
End Sub

由于 VBA 对象的生命周期似乎是确定性的,我想我可以像在 C++ 中那样用所谓的哨兵对象替换这种模式,这样异常退出(err.raise)的问题可以自动解决。

但是怎么做呢?我几乎不知道,因为我是 VBA 的新手,甚至不完全了解对象何时通过引用传递。理想情况下,我希望代码看起来像这样:

Sub Func()
dim Sentry
Set Sentry = CreateSentry(Application.EnableEvents,False)

' From now on we should not need to care if the variable was actually
' True or False beforehand, what kind of error handling is used in this function, etc.
End Sub

最佳答案

Application.EnableEvents 不是变量,而是属性。在 VB(A) 中不能像这样通过引用传递属性,编译器将创建当前属性值的临时副本,并且您的哨兵将在副本上“关闭”。

要以这种方式管理对象属性,您可以这样做:
创建一个类,命名它例如SentryForPropertiesVariant 并使用类似的代码:

Option Explicit

Private m_Obj As Object
Private m_PropertyName As String
Private m_OldValue As Variant


Public Sub Init(ByVal obj As Object, ByVal PropertyName As String, ByVal NewValue As Variant)
Set m_Obj = obj
m_PropertyName = PropertyName

m_OldValue = CallByName(obj, m_PropertyName, VbGet)
CallByName m_Obj, m_PropertyName, VbLet, NewValue
End Sub

Private Sub Class_Terminate()
If Not m_Obj Is Nothing Then
CallByName m_Obj, m_PropertyName, VbLet, m_OldValue
End If
End Sub

然后使用它:

Dim s As SentryForPropertiesVariant
Set s = New SentryForPropertiesVariant

s.Init Application, "EnableEvents", False

您还可以在模块中使用辅助函数:

Public Function CreateSentry(ByVal obj As Object, ByVal PropertyName As String, ByVal NewValue As Variant) As SentryForPropertiesVariant
Set CreateSentry = New SentryForPropertiesVariant

CreateSentry.Init obj, PropertyName, NewValue
End Function

此时使用变得更简单:

Dim s As SentryForPropertiesVariant
Set s = CreateSentry(Application, "EnableEvents", False)

在这种情况下,您可能希望将 Public Sub Init 替换为 Friend Sub Init

如果您打算将哨兵类存储在共享加载项 (.xla) 中,则无论如何您都必须拥有这样的辅助函数,因为加载项中定义的类不能从驻留在其他工作簿中的代码创建,所以解决方案是在与创建实例的类相同的工作簿中定义一个函数并将其返回给外部调用者。


最后,用With(类似C#的using)可以方便地控制这类哨兵的生命周期:

With CreateSentry(Application, "EnableEvents", False)
'Here EnableEvents is False
End With

'Here it's True

但是,这样做时,您应该记住 With类似于 using。如果您使用 GoTo 过早地跳出它,End With 语句 will not be executed ,这意味着保存哨兵实例的临时变量将持续到过程结束,并且在此之前属性不会恢复到其原始值。

所以不要跳出那些街区。如果绝对需要,请在 End With 之前创建一个标签并跳转到该标签。

关于vba - VBA 中的哨兵对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20718029/

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