2012-07-30 29 views
1

我在编写Excel的VBA宏时遇到语法选项问题。在VBA中,你可以调用对象的方法有两种不同的方式:语法选项在VBA Macro for Excel中创建错误

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的错综复杂,足以解释为什么会发生这种情况?

编辑:非常感谢解释!

回答

0

添加项目到一个集合没有被定义为返回值的函数,而是作为一个子程序:

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

当通过名称调用另一个子例程和发送参数(不添加“呼”的声明),您不需要添加括号。
当您调用函数时,需要添加圆括号,该函数会将值返回给变量

例子:

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 

让我知道,如果不明确。

+0

这将是正确的。在我VBA中,我通常会调用函数来返回执行例程的值和子集(如果您想将值分配给主子变量,仍然可以通过ref发送参数)。 Indd,如果您调用返回值的函数,则始终使用括号。 – Trace 2012-07-30 16:32:47

+0

+1,但当天票数不足。 : - / – Gaffi 2012-08-13 16:15:44

0

This Daily Dose of Excel conversation will be helpful。

当你使用括号时,你迫使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,就像你的问题一样。

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属性,如上面在其他答案中所述。

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