在为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': Object不支持此属性或方法
但是调用GetFundList.Add newFund
完全没问题。
有没有人能够理解VBA的复杂性,足以解释为什么会发生这种情况?
编辑:非常感谢您的解释!
答案 0 :(得分: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
如果不清楚,请告诉我。
答案 1 :(得分:0)
此Daily Dose of Excel conversation会有所帮助。
当您使用括号时,您强制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,就像您的问题一样。
答案 2 :(得分: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属性,如上面其他答案中所述。
第二个是,意图捕获或使用返回值而调用的函数需要围绕整个参数列表的extra(),而调用函数(或子函数)而无意捕获或使用返回值(例如作为语句)必须在参数列表周围没有那些相同的()被调用。这些surround()不使用.Value转换参数列表。当参数列表只有一个参数时,这种区别可能特别令人困惑。