Excel 输入左括号时崩溃

Excel crash when typing open parenthesis

这是一个我不明白的。

给定这个 class 模块(精简到重现崩溃所需的最低限度):

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "TestCrashClass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

Public Function Init() As TestCrashClass
Attribute Init.VB_UserMemId = 0
    Dim tcc As New TestCrashClass
    Set Init = tcc
End Function

Public Property Get Data() As String
    Data = "test data"
End Property

谁能告诉我为什么 Excel 在我输入这段代码时完全乱码:

Sub MakeExcelCrash()
    With TestCrashClass(

在这一点上,我这个可爱的消息:

即使我输入了一个没有括号的完整过程,然后尝试稍后添加它们,我也会遇到同样的崩溃。

让我 Excel 不崩溃的唯一方法是 copy/paste 从其他地方到这行代码的一组 ()

 Sub MakeExcelCrash()
     With TestCrashClass()
         Debug.Print .Data
     End With
 End Sub

如果 Init() 方法有一个参数——即使是一个可选参数——它在输入左括号时也不会崩溃。

我更好奇为什么会发生这种情况,而不是解决它的方法;它实际上并没有经常出现在我的代码中,当它出现时我可以通过改变方法来修复它,但我真的很沮丧,因为我不知道是什么导致了这些崩溃。所以也许对 VBA 的内部工作了解更多的人可以向我解释一下?

听起来像是某种腐败。我以前有过 Excel 像这样的非理性行为,通常是在大型项目中,解决它的唯一方法是将所有 类 等拖到一个新项目中。

我怀疑这是因为 Excel 没有真正删除 类、模块、工作表等已删除的内容。由于文件大小,您可以看出这一点。

据我所知,Access 中没有压缩和修复功能

正如@TimWilliams 指出的那样,有一个默认成员 returns same class(或 class 循环的一个实例例如 ParentClass.ChildClass.ParentClass.ChildClass... 其中 ParentClass 和 ChildClass 都有默认成员),并且在某些语法情况下使用时,例如 With 块,将导致 VBE 尝试解析默认成员。

第一个括号使 VBE 假设必须有一个方法,索引为 get 或数组索引,它将接受一个参数,因此它开始解析最终目标成员。

因此 不完整 行,光标位于括号后:

With TestCrashClass(

实际上等同于:

With TestCrashClass.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init.Init '....You're inquisitive scrolling this far over, but you get the point.

在某些时候,您的系统或 VBE 会耗尽资源并以热核 group-hug 的优雅和镇定退出。

+1 即兴创作一对括号 copy/pasta。

您甚至不需要 With 块。 任何 尝试在 class 名称取下 Excel 后键入 (

问题是您将 VB_PredeclaredId 设置为 true,而默认成员正在尝试 return 本身。当您将调试器附加到垂死的 Excel 实例时,您可以看到根本问题是堆栈溢出:

Unhandled exception at 0x0F06EC84 (VBE7.DLL) in EXCEL.EXE: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00212FFC).

当您键入 With TestCrashClass( 时,VBA 开始在 indexer默认 属性,因为 Init() 没有任何属性。例如,考虑 Collection。您可以像这样使用默认的 属性 的 (Item) 索引器:

Dim x As Collection
Set x = New Collection
x.Add 42
Debug.Print x(1)   '<--indexed access via default member.

这完全等同于Debug.Print x.Items(1)。这是您开始 运行 遇到问题的地方。 Init() 没有参数,因此 VBA 开始向下钻取默认成员以找到第一个具有索引器的成员,以便 IntelliSense 可以显示参数列表。它开始这样做:

x.[default].[default].[default].[default].[default]...

在你的例子中,它创建了一个无限循环,因为 [default] returns x。同样的事情发生在上面的 Collection 代码中(除了它找到一个):

加上你有一个默认实例,最终结果是这样的:

Private Sub Class_Initialize()
    Class_Initialize
End Sub