在大型项目上使用接口时出现错误

Cri*_*use 14 vba interface implements

对于较大的 VBA 项目(40,000 多行代码),我无法正确使用接口,因为应用程序(我主要使用 Excel)会经常崩溃。显然,这是因为代码不能保持编译状态(根据我的理解,VBA 代码被编译为 P 代码,稍后解释)。当 VBA 项目受密码保护时,我主要会得到这种行为。

当我打开托管文档时,调试/编译菜单几乎从不“变灰”:
在此处输入图片说明

文章描述了同样的情况。转至第 2.3 节

例如:
IClass接口:

Option Explicit

Public Property Get SomeProperty() As Double
End Property
Run Code Online (Sandbox Code Playgroud)

Class1

Option Explicit

Implements IClass

Private Property Get IClass_SomeProperty() As Double
    IClass_SomeProperty = 0
End Property
Run Code Online (Sandbox Code Playgroud)

标准模块中的代码:

Option Explicit

Sub TestInterface()
    Dim obj As IClass
    
    Set obj = New Class1
    Debug.Print obj.SomeProperty 'Crashes here on large projects only
End Sub
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,Debug.Print obj.SomeProperty如果项目很小,该行可以正常工作并在“立即”窗口中打印 0。但是,在大型项目中,调用此行时应用程序会崩溃。在IClass_SomeProperty没有达到(记录到文件阐明了这一点)。

正如上面提到的文章,有一些方法可以暂时避免这个问题:

  1. 重新编译解决了问题(并非总是如此),但在下次打开文档时可能会发生崩溃,或者它可能会持续几天(假设文件每天都打开)
  2. When option 1 is not working, deactivating all Implementsstatements in the entire project using the Find/Replace window, then compiling and then reactivating the statements back. 同样,这可以工作几个小时或几天,但不可避免地会在不久的将来发生崩溃

由于 VBA 项目受密码保护,并且许多人都在使用这些支持 VBA 的文档(在我的例子中是工作簿),应用临时修复程序根本没有帮助。

我发现避免崩溃并仍然获得接口好处的唯一方法是使用条件编译。基本上,我只将接口用于开发,然后切换到后期绑定用于生产。显然,这会带来很多麻烦。

上面的例子变成
Class1::

Option Explicit

#Const USE_INTERFACES = True

#If USE_INTERFACES Then
Implements IClass
#End If

Private Property Get IClass_SomeProperty() As Double
    IClass_SomeProperty = Me.SomeProperty
End Property

Public Property Get SomeProperty() As Double
    SomeProperty = 0
End Property
Run Code Online (Sandbox Code Playgroud)

请注意,所有接口方法都必须复制并公开,以便后期绑定成为一种选择。

标准模块中的代码:

Option Explicit

#Const USE_INTERFACES = True

Sub TestInterface()
    #If USE_INTERFACES Then
        Dim obj As IClass
    #Else
        Dim obj As Object
    #End If
    
    Set obj = New Class1
    Debug.Print obj.SomeProperty
End Sub
Run Code Online (Sandbox Code Playgroud)

在开发新功能时,我遵循以下步骤:

  1. 打开#Const USE_INTERFACES = True使用查找所有出现/替换
  2. 添加新功能
  3. 转,#Const USE_INTERFACES = False以便代码在后期绑定时运行并且不会崩溃

我已经遇到这个错误至少 3 年了。如果可以的话,我显然会避免条件编译解决方法。

有没有办法在不访问VBA 项目对象模型的情况下保持 VBA 项目的编译(假设在打开文档时运行一个过程)?我不能选择打开对VBA 项目对象模型信任访问

我很欣赏这个错误不容易重新创建,除非您手头有一个大型 VBA 项目。

编辑 1

@PEH 在评论中提出了一个很好的观点:这个问题适用于xlsmxlsb文件(Excel)。

S M*_*den 2

我也开始使用接口(几年前),因为我认为它们是正确的 COM(而且它们确实是),但我也遇到了问题。所以,我停止使用它们。

除此之外,如果双击具有普通代码的方法,您会跳转到代码实现,但如果使用接口,您会跳转到一个空方法(这是不令人满意的)。

如果您确实有一个类 Foo,它表达了足以分解为单独接口 IBar 的不同行为,那么为什么不将 IBar 分解为实际的单独类 Bar,然后将 Bar 的实例设置为 Foo 的公共属性呢?

这只是一个建议。据我所知,没有其他 VBA 修复程序,而且 Microsoft 现在也不太可能修复此问题。

如果您想保留类/接口设计,您始终可以将代码迁移到 VisualBasic.Net。

如果有人真正解决这个问题,我会很高兴。