语法选项在Excel的VBAmacros中创build错误

在编写Excel的VBAmacros时遇到语法选项问题。 在VBA中,可以通过两种不同的方式调用对象的方法:

foo.bar(arg1, arg2) 

要么

 foo.bar arg1, arg2 

我绝对厌恶第二种语法,因为我觉得它没有任何的清晰度,所以我通常坚持第一种select。 但是,我遇到了使用第一个选项创build错误,而第二个执行正常的情况。 (这也许是我的代码中的其他问题的一个指标。)这是罪魁祸首的代码:

 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是我创build的类,基本上只是一个结构; 它有三个属性在循环期间被设置。

基本上,当我调用GetFundList.Add(newFund)出现以下错误:

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

但是调用GetFundList.Add newFund是完全正确的。

有没有人了解VBA的错综复杂,足以解释为什么会发生这种情况?

编辑:非常感谢解释!

将项目添加到集合中没有定义为返回值的函数,而是作为子例程:

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

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

例:

 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 

让我知道如果不清楚。

这个每日剂量的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的默认属性。 但是,第一个将产生一个“范围”types,而第二个例子中的types是A1中的数据types。 换句话说,第一个为范围添加一个范围,第二个范围的内容。

另一方面,这工作:

 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,就像你的问题。

这是看同样的事情的另一种方式。

假设单元格A1包含stringHi!

 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!" eg contents of A1 aka Range("A1").Value; conversion to value during let = assignment Let r = (Range("A1")) ' set r to "Hi!" eg 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 

我只是补充一点,以帮助说明这里有两件事情可以合并。

首先是()在一个expression式中将该项目转换为其Value属性,如上面在其他答案中所述。

第二个是调用的函数意图捕获或使用返回值需要extra()围绕整个参数列表,而函数(或子的)调用而不意图捕获或使用返回值(例如作为语句)必须调用没有那些围绕参数列表的same()。 这些surround()不使用.Value转换参数列表。 当参数列表只有一个参数时,这个区别可能会特别混乱。