为什么缺少某些类型的“Set”运行时错误而不是编译错误?

问题描述 投票:3回答:2

给出以下VBA代码,假设Something只是一个VBA类模块....

Public Type Foo
    SomeThing As Something
End Type

Public Sub TestFoo()
    Dim x As Foo
    With x
        'Correct way to do it
        Set .someThing = New Something
    End With

    With x
        'This is wrong but realized only as a RTE 
        '438: Object doesn't support this property or method
        .SomeThing = New Something
    End With
End Sub

相反,如果您将类型更改为VBA.Collection,如下所示:

Public Type Foo
    SomeThing As VBA.Collection
End Type

Public Sub TestFoo()
    Dim x As Foo

    With x
        .SomeThing = New VBA.Collection
    End With
End Sub

现在这是一个编译错误,使用Argument Not Optional。这显然是错误的,但为什么它只是VBA.Collection的编译时错误?

vba
2个回答
3
投票

这在VBA语言规范中有解释。 With块中赋值的语义是由语句是Set语句还是Let语句驱动的。在这种情况下,它是一个Let声明:

With x
    .SomeThing = New Something
End With

请注意,在VBA语法中,关键字Let是可选的(已废弃):

let-statement = ["Let"] l-expression "=" expression

Set语句中,Set关键字是必需的:

set-statement = "Set" l-expression "=" expression

With区块内部,l-expression基本上是UDT成员,但如果直接使用x,则完全相同的行为适用。

在评估Let表达式时,语义在section 5.4.3.8中描述:

静态语义。

如果满足以下任何条件,则此语句无效:

  • 无法将<expression>计算为简单数据值(第5.6.2.2节)。

接下来是5.6.2.2 (Evaluation to a simple data value),以下运行时语义适用(仅适用规则):

运行时语义。

在运行时,简单数据值的值和值类型是根据表达式的分类确定的,如下所示:

  • 如果表达式的值类型是特定类: 如果源对象具有公共默认属性Get或公共默认函数,并且此默认成员的参数列表与包含0个参数的参数列表兼容,则简单数据值的值是将此默认成员作为简单数据值进行评估的结果。 否则,如果源对象没有公共默认属性Get或公共默认函数,则引发运行时错误438(对象不支持此属性或方法)。

因此SomeThing As Something的运行时错误438。

使用CollectionLet静态语义仍然适用,但它无法使用5.6.2.2的静态语义(这给出了编译错误)。同样,省略了前面不适用的语义:

静态语义。可以评估以下类型的表达式以生成简单的数据值:

  • 分类为值表达式的表达式可以基于以下规则评估为简单数据值: 如果表达式的声明类型是特定类: 如果此类具有公共默认属性Get或函数,并且此默认成员的参数列表与包含0个参数的参数列表兼容,则简单数据值评估将重新启动,就好像此默认成员是表达式一样。

Collection的默认成员是一个函数(.Item),它采用单个参数Index。在此代码中,未提供参数,因此参数列表不兼容:

With x
    .SomeThing = New VBA.Collection
End With

因此Argument Not Optional编译错误。


1
投票

在输入问题时,让我感到震惊的是VBA.Collection有一个默认成员。因此,编译器将.Something = New VBA.Collection解释为默认成员的赋值...除了Item是索引属性。这就解释了为什么我们得到Argument not optional这对于使用Set语句来说是一个非常奇怪的错误。

相反,VBA类模块可能根本没有默认成员,因此没有索引属性+默认成员来触发编译时错误。但是,这也意味着在运行时才会捕获错误的语法。

© www.soinside.com 2019 - 2024. All rights reserved.