键入左括号

时间:2017-02-06 19:38:05

标签: 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

当我输入此代码时,有人能告诉我为什么Excel完全崩溃了:

Sub MakeExcelCrash()
    With TestCrashClass(

此时,我发出了这条可爱的信息:

Excel crash - oops!

即使我在没有违规括号的情况下输入完整的程序,然后尝试稍后添加它们,我也会遇到同样的崩溃。

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

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

如果Init()方法有一个参数 - 甚至是一个可选参数 - 它在键入开始参数时不会崩溃。

我对为什么发生这种情况比对周围的方式更感兴趣;它实际上并没有经常出现在我的代码中,当它发生时,我可以通过改变方法来修复它,但我真的很沮丧,因为我不知道是什么造成了什么这些崩溃。那么也许有更多了解VBA内部工作的人可以向我解释一下吗?

3 个答案:

答案 0 :(得分:11)

您甚至不需要With块。 任何尝试在类名称关闭Excel后键入(

问题是您将VB_PredeclaredId设置为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.

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

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

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

IntelliSense on open parens

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

Private Sub Class_Initialize()
    Class_Initialize
End Sub

答案 1 :(得分:9)

正如@TimWilliams所指出的,拥有一个默认成员,它返回相同类的实例(或类循环,例如。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耗尽了资源,并以热核团队的拥抱和优势退出。

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

答案 2 :(得分:-4)

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

我怀疑它发生是因为Excel没有真正删除已删除的类,模块,工作表等。你可以告诉这个因为文件大小。

没有Compact和Repair功能,就像在Access中一样,据我所知