Excel 带日志记录的加载项 class:如何应对 VBA 状态丢失?

Excel add-in with logging class: How to react to VBA state loss?

设置

我正在开发和维护一个 Excel 插件,它在 Excel 的功能区 UI 中带有自己的控件选项卡。我以前遇到过状态丢失的问题(意思是丢失所​​有具有全局范围的变量,静态变量等,当然包括我对 RibbonUI 的引用)。关于功能区引用,我通过包含一个“重置功能区”按钮“解决”了这个问题,该按钮从持久存储的指针中恢复引用,然后使功能区无效。虽然肯定不是最优雅的,但这部分工作得很好。

然而,在引入日志记录class之后,状态丢失问题再次困扰着我。记录器在 ThisWorkbook 的模块中实例化:

Private Sub Workbook_Open()
    Set LogToFile = SingletonFactory.getToFileLogger
End Sub

然后投入工作,例如,如下:

Private Sub buttonReloadObjects_onAction(ByVal control As IRibbonControl)
    LogToFile.trace "Event firing: buttonReloadObjects_onAction"
    ' more stuff happening...
    invalidateRibbon ' restores ribbon object and invalidates it
End Sub

加载项加载时会实例化记录器,这样我就可以在加载项代码的范围内自由记录我想要的任何内容。它有几个日志记录级别,如 trace/debug/error/... 和一些其他方法。通常它工作得很好 - 直到状态丢失命中(通常由不相关的错误引起,然后单击“结束”)。

状态丢失

此时 VBA 环境忘记了我的 LogToFile 对象的存在并且不再起作用,因为每次单击功能区控件都会触发 runtime error 91: Object variable or with block variable not set 指向到第一行包含对 LogToFile.

的引用

解决方案?

现在,不用像放置

这样疯狂的变通办法了
if not isObject(LogToFile) then
    Set LogToFile = SingletonFactory.getToFileLogger
end if
LogToFile.trace "Message"

任何 出现 LogToFile 之前,我能想出的唯一真正的“解决方案”是将我所有的记录器调用包装在函数中(驻留在一个标准模块)并在我想向日志发送内容时调用这些函数。这样我就可以在需要对象之前捕获丢失的对象引用,并且避免调用未实例化对象的方法。
然而,在将所有内容整齐地封装在 class 模块之后,我觉得很奇怪,甚至可能是错误的(?),沿着这条路走下去。


那么,对于记录器实例丢失的问题,是否有“合适”的解决方案呢?还是我建议的方法已经尽可能合适了?


注意:这个问题当然不是日志记录 classes 特有的。它会影响所有全局变量,尤其是我的 ApplicationEventClass。由于在代码的所有入口点周围频繁使用记录器,这个问题恰好是最明显的。

您只需要一个 returns 原始变量或重置它的函数。如果您调用该函数 LogToFile 除了删除多余的 Workbook_Open 代码外,您不需要更改任何其他代码。所以:

Function LogToFile() As WhateverVariableType
Static temp as WhateverVariableType
If temp is Nothing then Set temp = SingletonFactory.getToFileLogger
Set LogToFile = temp
End Function

通过这种方式,您在编写代码时仍将受益于 Intellisense。

注意:您可能实际上不需要临时变量 - 这取决于是否有您想要保留的设置。如果有,你可能也想在函数中重置它们。