2012-07-30 26 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轉換參數列表。當參數列表只有一個參數時,這個區別可能會特別混亂。