键入左括号时Excel崩溃

Pat*_*nne 11 excel vba vbe

这是我不明白的一个.

鉴于此类模块(剥离到重现崩溃所需的最低限度):

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
Run Code Online (Sandbox Code Playgroud)

任何人都可以告诉我为什么当我输入以下代码时Excel完全崩溃:

Sub MakeExcelCrash()
    With TestCrashClass(
Run Code Online (Sandbox Code Playgroud)

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

Excel崩溃 - 哎呀!

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

我能让Excel不崩溃的唯一方法是将一组()从其他地方复制/粘贴到这行代码中.

 Sub MakeExcelCrash()
     With TestCrashClass()
         Debug.Print .Data
     End With
 End Sub
Run Code Online (Sandbox Code Playgroud)

如果该Init()方法具有参数 - 甚至是可选参数 - 它在键入开始paren时不会崩溃.

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

Com*_*ern 11

你甚至不需要With块. 任何(在类名后面输入的尝试都会使Excel失效.

问题是您将VB_PredeclaredIdset设置为true,并且默认成员正在尝试返回自身.将调试器附加到垂死的Excel实例时,您可以看到基础问题是堆栈溢出:

EXCEL.EXE中0x0F06EC84(VBE7.DLL)处的未处理异常:0xC00000FD:堆栈溢出(参数:0x00000001,0x00212FFC).

当您键入时With TestCrashClass(,会发生什么是VBA开始在默认属性上查找索引器,因为Init()它没有任何属性.例如,考虑一个Collection.您可以使用默认属性的(Item)索引器,如下所示:

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

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

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

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

开放式parens上的智能感知

抛出你有一个默认实例的事实,最终结果是这样的:

Private Sub Class_Initialize()
    Class_Initialize
End Sub
Run Code Online (Sandbox Code Playgroud)


Thu*_*ame 9

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

第一个括号使VBE假定必须有一个方法,索引get或数组索引将接受一个参数,因此它将启动以解析最终目标成员.

所以不完整的行,光标位于括号后面:

With TestCrashClass(
Run Code Online (Sandbox Code Playgroud)

实际上是有效的:

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.
Run Code Online (Sandbox Code Playgroud)

在某些时候,你的系统或VBE耗尽了资源,并以热核团队拥抱的优雅和平衡退出.

用括号副本/面食即兴创作+1.

  • 热核团 - 拥抱得到我的+1 (3认同)
  • 我不得不承认我一直向右滚动,只是为了看你能走多远.谢谢! (3认同)