2013-12-21 7 views
1

Я вижу коды со следующей схемой Повсеместно в Интернете и в моих собственных проектах:объекты Sentry в VBA

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 

ответ

5

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# 's using):

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

'Here it's True 
+1

Спасибо, это смехотворно прекрасный ответ за такое короткое время! Я подтвердил, что это работает полностью, как я ожидал, единственным недостатком будет то, что из-за имени свойства, переданного как строка, ошибка должна быть обнаружена только во время выполнения. Может быть, я должен определить часто используемые имена свойств как константы. – mnish

0

Модули класса может быть использована для этого, как вы можете задать код для запуска при создании экземпляра модуля класса, и, что особенно важно, когда счетчик ссылок на объект падает до нуля.

В частности, вы можете поместить код в

Private Sub Class_Initialize() 

и

Private Sub Class_Terminate() 
+0

Downvote? Я неправильно понял? – Bathsheba

+0

OP уже заявляет, что («время жизни объектов VBA кажется детерминированным»).Проблема заключается в передаче чего-то классу, который может быть использован для восстановления внешнего значения позже (у VB нет явных указателей). – GSerg

+0

Я оставлю это на некоторое время, чтобы узнать, насколько это полезно для OP. – Bathsheba

Смежные вопросы