【发布时间】:2021-03-10 12:02:31
【问题描述】:
标题中的问号只是因为我非常不愿意将任何事情称为编译器错误,但在这种情况下,如果有人能以任何其他方式解释这种行为,我会感到惊讶。
重现问题的代码非常非常简单。在标准模块中,我们有以下内容:
Sub CompilerBug()
Dim oClass As cClass
Set oClass = New cClass
If False Then
Debug.Print "This doesn't print, as it shouldn't."
End If
If Falsee(oClass.Clone) Then
Debug.Print "This does print, although it shouldn't!"
End If
End Sub
Public Function Falsee(oClass As cClass) As Boolean
Falsee = False
End Function
我们在名为 cClass 的类模块中定义了一个类 (cClass),包含以下代码:
Public Function Clone() As cClass
Dim oClass As cClass
Set oClass = New cClass
Set Clone = oClass
End Function
Private Sub Class_Terminate()
End Sub
代码是不言自明的。 第二个 if 语句被输入,尽管函数 Falsee 返回 False,无论输入如何!当类中的函数被替换为类似的Public Property Get时,可以观察到相同的结果。
出于复制的目的,我在我的 Office 365 Excel,64 位,版本 2011(内部版本 13426.20274)中遇到了这种行为,这是当前最新版本的 excel。我还在我的 Word VBA IDE 中测试了这个确切的代码,结果完全相同。
“证明”:
我不知道是什么导致了这种行为,但这里有一些线索:
如果我们将 sub 中的代码重写为:
Sub CompilerBug()
Dim oClass As cClass
Set oClass = New cClass
Dim bFalse As Boolean
bFalse = Falsee(oClass.Clone)
If bFalse Then
Debug.Print "This doesn't print, as it shouldn't."
End If
End Sub
(为简洁起见,省略了第一个 if 语句。)代码按预期执行,因此在 if 的条件下直接调用函数至关重要 声明(通常不应该有所作为)。
下一个有趣的线索如下(假设我们再次使用带有 If Falsee(oClass.Clone) Then 的错误子代码):
如果我们从类模块中删除以下内容:
Private Sub Class_Terminate()
End Sub
if 语句按预期工作,并且没有打印任何内容!因此,在评估 If 语句期间执行的 Terminate 事件以某种方式将事情搞砸了,但 Class_Terminate() 子甚至不包含任何代码!接下来的事情不应该有所作为!
这个想法得到了进一步的支持,当我们在模块中声明一个公共变量时,在顶部添加Public poClass As cClass并将函数代码重写为:
Public Function Falsee(oClass As cClass) As Boolean
Set poClass = oClass
Falsee = False
End Function
现在在执行 If 语句期间不会调用 Terminate 事件,因为在执行 If 语句期间类的实例不会超出范围,因此,If 语句正确评估 - 行没有被打印出来。
显然,在评估 If 语句期间执行的 Terminate-event 不可能是全部,因为这种情况一直在发生。它似乎也与被终止的对象的范围以及参数传递给函数的方式有关。例如,以下不会产生相同的行为:
模块代码:
Sub CompilerBug()
Dim oClass As cClass
Set oClass = New cClass
If Falsee(oClass.CreateAndDestroyObject) Then
Debug.Print "This doesn't print, as it shouldn't."
End If
End Sub
Public Function Falsee(lng As Variant) As Boolean
Falsee = False
End Function
在类模块中:
Public Function CreateAndDestroyObject() As Long
Dim oClass2 As cClass
Set oClass2 = New cClass
Set oClass2 = Nothing
End Function
Private Sub Class_Terminate()
End Sub
总而言之,该行为发生在以下情况:
一个类的方法返回同一个类的一个实例,并且这个方法在一个 If 语句的条件内被调用,作为一个函数的参数,并且这个类的实例(由该方法创建) 然后超出该函数内部的范围,并且类的终止事件被调用(并作为代码存在)。 在这种情况下,无论函数的返回值如何,都会输入 if 语句。
对我来说,还有很多问题......为什么 Terminate 事件在这种情况下会产生影响?我的任何代码是否应该产生未定义的行为,或者这实际上是一个错误?是否还有其他情况下 If 语句不能按预期方式工作?究竟是什么导致了这个错误?
在 32 位版本的 Excel 中似乎不存在该问题。
【问题讨论】:
-
在 Excel O365 32 位中,我无法重现您的问题。什么都没有打印,并且逐行执行,每一行都执行。
-
@RonRosenfeld 我现在也在另一台 PC 上尝试了 32 位版本,我也无法在那里重现它。我也刚刚问了一位同样运行 64 位版本的同事,他能够重现它。
-
很奇怪。不会想到“位”会在这样的事情上有所作为。
-
不精通 VBA,但这可能与将“false”拼写为“falsee”有关吗?
-
@TylerH 没有。 VBA if 语句的工作方式如下:如果条件评估为
True,则输入该语句。如果条件计算结果为False,则语句跳转到下一个ElseIf、Else或End If,以先到者为准。 (当然,忽略If False Then和下一个ElseIf部分之间的嵌套 if 语句......)它与评估“成功”的函数无关。如果函数不成功,如果没有适当的错误处理,程序将抛出错误。
标签: excel vba oop if-statement compiler-bug