本頁列出使用程序時可能發生的一些常見問題。
從函數程序傳回陣列類型
如果程序傳回陣列資料類型,則 Function 無法使用名稱將 Function 值儲存在陣列的元素中。 如果您嘗試這樣做,編譯器會將其解譯為對 .Function 下列範例會產生編譯器錯誤:
Function AllOnes(n As Integer) As Integer()
For i As Integer = 1 To n - 1
' The following statement generates a COMPILER ERROR.
AllOnes(i) = 1
Next
' The following statement generates a COMPILER ERROR.
Return AllOnes()
End Function
此陳述式AllOnes(i) = 1會產生編譯器錯誤,因為它似乎使用錯誤資料類型的引數 (純量Integer而不是Integer陣列) 進行呼叫AllOnes。 陳述式 Return AllOnes() 會產生編譯器錯誤,因為它似乎沒有引數來呼叫 AllOnes 。
正確做法: 若要能夠修改要傳回的陣列元素,請將內部陣列定義為局部變數。 下列範例編譯時沒有錯誤:
Function AllOnes(n As Integer) As Integer()
Dim iArray(n - 1) As Integer
For i = 0 To n - 1
iArray(i) = 1
Next
Return iArray
End Function
程序呼叫未修改的引數
如果您想要允許程序變更呼叫程式碼中引數基礎的程式設計元素,則必須透過參考傳遞它。 但是,即使您依值傳遞參考類型引數,程序也可以存取它。
基礎變數。 若要允許程序取代基礎變數元素本身的值,程序必須宣告參數 ByRef。 此外,呼叫程式碼不得將引數括在括弧中,因為這會覆寫
ByRef傳遞機制。參考類型元素。 如果您宣告參數 ByVal,則程序無法修改基礎變數元素本身。 不過,如果引數是參考類型,則程序可以修改它所指向之物件的成員,即使它無法取代變數的值也一樣。 例如,如果引數是陣列變數,則程序無法為其指派新的陣列,但可以變更其一或多個元素。 變更的元素會反映在呼叫程式碼的基礎陣列變數中。
下列範例定義兩個程序,依值取得陣列變數,並對其元素進行操作。 程序 increase 只是將一個添加到每個元素中。 程序 replace 會將新陣列指派給參數 a() ,然後將一個新增至每個元素。 不過,重新指派不會影響呼叫程式碼中的基礎陣列變數,因為 a() 宣告了 ByVal。
Public Sub increase(ByVal a() As Long)
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
Public Sub replace(ByVal a() As Long)
Dim k() As Long = {100, 200, 300}
a = k
For j As Integer = 0 To UBound(a)
a(j) = a(j) + 1
Next j
End Sub
下列範例會呼叫 increase 和 replace:
Dim n() As Long = {10, 20, 30, 40}
Call increase(n)
MsgBox("After increase(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
Call replace(n)
MsgBox("After replace(n): " & CStr(n(0)) & ", " &
CStr(n(1)) & ", " & CStr(n(2)) & ", " & CStr(n(3)))
第一個 MsgBox 呼叫顯示「增加後(n):11、21、31、41」。 因為 n 是參考類型, increase 可以變更其成員,即使已傳遞 ByVal。
第二個 MsgBox 呼叫顯示「替換後(n):11、21、31、41」。 因為 傳遞了 ,所以n不能透過為變數指派一個新陣列來修改變數n。 replaceByVal 當建立新的陣列實例k並將其指派給局部變數a時replace,它會遺失呼叫程式碼傳入的參考n。 當它遞增 的 a成員時,只有本機陣列 k 受到影響。
正確做法: 若要能夠修改基礎變數元素本身,請透過引用傳遞它。 下列範例顯示宣 replace 告的變更,允許它在呼叫程式碼中將一個陣列取代為另一個陣列:
Public Sub replace(ByRef a() As Long)
無法定義多載
如果您想要定義程序的多載版本,則必須使用相同的名稱,但不同的簽章。 如果編譯器無法將您的宣告與具有相同簽章的多載區分開來,則會產生錯誤。
程序的 簽章 是由程序名稱及參數清單所決定。 每一個多載必須與所有其他多載具有相同的名稱,但必須在簽章的至少一個其他元件中與所有多載不同。 如需相關資訊,請參閱 程序多載。
下列項目即使與參數清單相關,也不是程序簽章的元件:
- 程序修飾詞關鍵字,例如
Public、 和SharedStatic。 - 參數名稱。
- 參數修飾詞關鍵字,例如
ByRef和Optional。 - 傳回值的資料類型 (轉換運算子除外)。
您無法透過僅變更上述一個或多個項目來多載程序。
正確做法: 若要能夠定義程序多載,您必須變更簽章。 因為您必須使用相同的名稱,所以必須改變參數的數目、順序或資料類型。 在一般程序中,您可以變更類型參數的數目。 在轉換運算子 (CType 運算子) 中,您可以變更傳回類型。
使用 Optional 和 ParamArray 引數的重載解析
如果您要使用一或多個 選擇性 參數或 ParamArray 參數來多載程序,則必須避免複製任何 隱含多載。 如需相關資訊,請參閱 多載程序中的考量。
呼叫錯誤版本的多載程序
如果程式有數個多載版本,您應該熟悉其所有參數清單,並瞭解 Visual Basic 如何解析多載之間的呼叫。 否則,您可以呼叫預期以外的多載。
當您決定要呼叫哪個多載時,請小心遵守下列規則:
- 提供正確數量的引數,並以正確的順序。
- 理想情況下,您的引數應該具有與相應參數完全相同的資料類型。 在任何情況下,每個引數的資料類型都必須擴大到其對應參數的資料類型。 即使將 Option Strict 陳述式 設定為
Off,也是如此。 如果多載需要從引數清單中進行任何縮小轉換,則該多載不符合呼叫資格。 - 如果您提供需要加寬的引數,請使其資料類型盡可能接近對應的參數資料類型。 如果兩個或多個多載接受您的引數資料類型,編譯器會解析您對呼叫呼叫的多載,以呼叫最少的加寬量。
您可以在準備引數時使用 CType 函數 轉換關鍵字來減少資料類型不相符的機會。
過載解析失敗
當您呼叫多載的程序時,編譯器會嘗試消除除一個多載之外的所有多載。 如果成功,它會解析對該多載的呼叫。 如果它消除了所有多載,或者如果它無法將合格多載減少到單一候選,則會產生錯誤。
下列範例說明多載解決程式:
Overloads Sub z(ByVal x As Byte, ByVal y As Double)
End Sub
Overloads Sub z(ByVal x As Short, ByVal y As Single)
End Sub
Overloads Sub z(ByVal x As Integer, ByVal y As Single)
End Sub
Dim r, s As Short
Call z(r, s)
Dim p As Byte, q As Short
' The following statement causes an overload resolution error.
Call z(p, q)
在第一次呼叫中,編譯器會消除第一個多載,因為第一個引數 (Short) 的類型會縮小到對應參數 ()Byte 的類型。 然後,它會消除第三個多載,因為第二個多載 (Short 和 Single) 中的每個引數類型都會擴大到第三個多載 (Integer 和 Single) 中的對應類型。 第二個多載需要較少的加寬,因此編譯器會使用它進行呼叫。
在第二次呼叫中,編譯器無法根據縮小來消除任何多載。 它會消除第三個多載,原因與第一次呼叫相同,因為它可以呼叫第二個多載,且引數類型的擴寬較少。 不過,編譯器無法在第一個和第二個多載之間解析。 每個都有一個已定義的參數類型,該類型會加寬到另一個中的對應類型 (Byte 至 Short,但 Single 至 Double)。 因此,編譯器會產生多載解析錯誤。
正確做法: 若要能夠呼叫多載的程式而不會模明,請使用 CType 函式 將引數資料類型與參數類型相符。 下列範例顯示強制解析為第二個多載的呼叫 z 。
Call z(CType(p, Short), CType(q, Single))
使用 Optional 和 ParamArray 引數的重載解析
如果程式的兩個多載具有相同的簽章,但最後一個參數在其中一個參數中宣告為 Optional ,而在另一個參數中宣告 ParamArray ,編譯器會根據最接近的相符專案解析對該程式的呼叫。 如需詳細資訊,請參閱 多載解析。