1

在为 Excel 编写 VBA 宏时,我遇到了一些语法选项问题。在 VBA 中,您可以通过两种不同的方式调用对象上的方法:

foo.bar(arg1, arg2)

或者

foo.bar arg1, arg2

我绝对讨厌第二种语法,因为我发现它缺乏任何清晰度,所以我通常坚持第一种选择。但是,我遇到了一种情况,使用第一个选项会产生错误,而第二个选项执行得很好。(这可能表明我的代码中存在其他问题。)这是罪魁祸首代码:

Function GetFundList() As Collection
    Dim newFund As FundValues
    Range("A5").Select
    Set GetFundList = New Collection

    While Len(Selection.Value)
        Set newFund = New FundValues

        ' I set the fields of newFund and move Selection

问题出在下一行:

        GetFundList.Add newFund
    Wend
End Function

FundValues 是我创建的一个类,它本质上只是一个结构;它具有三个在循环期间设置的属性。

基本上,当我打电话时,GetFundList.Add(newFund)我收到以下错误:

运行时错误“438”:对象不支持此属性或方法

但是打电话GetFundList.Add newFund完全没问题。

有没有人足够了解 VBA 的复杂性来解释为什么会发生这种情况?

编辑:非常感谢您的解释!

4

3 回答 3

0

向集合中添加项不是定义为返回值的函数,而是定义为子例程:

Public Sub Add( _
   ByVal Item As Object, _
   Optional ByVal Key As String, _
   Optional ByVal { Before | After } As Object = Nothing _
)

当通过名称调用另一个子例程并发送参数时(不添加“Call”语句),您不需要添加括号。当您调用一个返回值给变量
的函数时,您需要添加括号。

例子:

Sub Test_1()
Dim iCnt As Integer
Dim iCnt_B As Integer
Dim iResult As Integer


iCnt = 2
iCnt_B = 3

fTest_1 iCnt, iResult, iCnt_B

End Sub

Public Function fTest_1(iCnt, iResult, iCnt_B)

iResult = iCnt * 2 + iCnt_B * 2

End Function

Sub Test_2()

Dim iCnt As Integer
Dim iCnt_B As Integer
Dim iResult As Integer


iCnt = 2
iCnt_B = 3

iResult = fTest_2(iCnt, iCnt_B)

End Sub

Public Function fTest_2(iCnt, iCnt_B)

fTest_2 = iCnt * 2 + iCnt_B * 2

End Function

如果不清楚,请告诉我。

于 2012-07-30T15:44:43.887 回答
0

这个Excel 对话的每日剂量将很有帮助。

当您使用括号时,您会强制 VBA 评估其中的内容并将结果添加到集合中。由于 NewFund 没有默认属性 - 我假设 - 评估不会产生任何结果,因此无法添加。如果没有括号,它将评估为类的实例,这就是您想要的。

另一个例子。这:

Dim coll As Collection
Set coll = New Collection
coll.Add Range("A1")
Debug.Print coll(1); TypeName(coll(1))

还有这个 ...

coll.Add (Range("A1"))
Debug.Print coll(1); TypeName(coll(1))

...两者都产生 debug.window 中 A1 中的任何内容,因为 Value 是 Range 的默认属性。但是,第一个将产生“范围”类型,而第二个示例中的类型是 A1 中的数据类型。换句话说,第一个向集合添加一个范围,第二个范围的内容。

另一方面,这有效:

Dim coll As Collection
Set coll = New Collection
coll.Add ActiveSheet
Debug.Print coll(1).Name

...这不会:

coll.Add (ActiveSheet)
Debug.Print coll(1).Name

因为 ActiveSheet 没有默认属性。你会得到一个运行时错误 438,就像你的问题一样。

于 2012-07-30T15:57:39.160 回答
0

这是看待同一件事的另一种方式。

假设单元格 A1 包含字符串 Hi!

Function SomeFunc(item1, item2)
    SomeFunc = 4
End Function

Sub Mac()
    ' here in both of the following two lines of code,
    '  item1 will be Variant/Object/Range, while item2 will be Variant/String:
    SomeFunc Range("A1"), (Range("A1"))
    Let i = SomeFunc(Range("A1"), (Range("A1")))

    'this following is a compile syntax error
    SomeFunc(Range("A1"), (Range("A1"))) 

    ' while here in both the following two lines of code, 
    '  item1 will be Variant/String while item2 will be Variant/Object/Range:
    SomeFunc ((Range("A1")), Range("A1")
    Let j = SomeFunc((Range("A1")), Range("A1"))

    'this following is a compile syntax error
    SomeFunc((Range("A1")), Range("A1"))

    Set r = Range("A1")       ' sets r to Variant/Object/Range
    Set r = (Range("A1"))     ' runtime error 13, type mismatch; cannot SET r (as reference) to string "Hi!" -- Strings are not objects in VBA
    Set r = Range("A1").Value ' runtime error (same)


    Let r = Range("A1")       ' set r to "Hi!" e.g. contents of A1 aka Range("A1").Value; conversion to value during let = assignment
    Let r = (Range("A1"))     ' set r to "Hi!" e.g. contents of A1 aka Range("A1").Value; conversion to value by extra ()'s
    Let r = Range("A1").Value ' set r to "Hi!" by explicit use of .Value 
End Sub

我只是添加这个来帮助说明这里发生了两件事,这可能是混为一谈的。

第一个是表达式中的 () 将项目转换为其 Value 属性,如上面其他答案中所述。

第二个是为了捕获或使用返回值而调用的函数需要额外的 () 围绕整个参数列表,而在没有意图捕获或使用返回值的情况下调用的函数(或子)(例如 as 语句)必须在没有调用的情况下调用那些围绕参数列表的相同 ()。这些周围的 () 不使用 .Value 转换参数列表。当参数列表只有一个参数时,这种区别可能特别令人困惑。

于 2012-07-31T01:23:47.823 回答