此页面列出了使用过程时可能发生的一些常见问题。
从函数过程返回数组类型
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 个调用显示“replace(n):11,21,31,41”。 由于n传递,ByValreplace因此无法通过向其分配新数组来修改变量n。 创建新数组实例k并将其分配给局部变量a时replace,它将失去通过调用代码传入的引用n。 当它递增成员时 a,仅影响本地数组 k 。
正确的方法: 若要能够修改基础变量元素本身,请通过引用传递它。 以下示例演示了允许它在调用代码中将一个数组替换为另一个数组的声明 replace 中的更改:
Public Sub replace(ByRef a() As Long)
无法定义重载
如果要定义过程的重载版本,则必须使用相同的名称,但使用不同的签名。 如果编译器无法将声明与具有相同签名的重载区分开来,则会生成错误。
过程的 签名 由过程名称和参数列表确定。 每个重载的名称必须与所有其他重载具有相同的名称,但必须在签名的其他至少一个组件中与所有这些重载不同。 有关详细信息,请参阅 过程重载。
以下项(即使它们与参数列表相关)不是过程签名的组件:
- 过程修饰符关键字,例如
Public,Shared和Static。 - 参数名称。
- 参数修饰符关键字,如
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和)中的每个自变量类型都扩大到第三个重载Integer(和SingleSingle)中的相应类型。 第二个重载需要较少的扩大,因此编译器使用它进行调用。
第二次调用中,编译器不能在缩小的情况下消除任何重载。 它消除第三个重载的原因与第一次调用中的原因相同,因为它可以调用第二个重载,参数类型的扩大较少。 但是,编译器无法解析第一个重载和第二个重载。 每个参数类型都有一个定义的参数类型,该类型扩展为另一个类型(ByteShort但Single要扩大到 Double)。 因此,编译器将生成重载解析错误。
正确的方法: 若要能够调用不含糊不清的重载过程,请使用 CType 函数 将参数数据类型与参数类型匹配。 下面的示例演示了对 z 它强制解析到第二个重载的调用。
Call z(CType(p, Short), CType(q, Single))
具有 Optional 和 ParamArray 参数的重载解析
如果过程的两个重载具有相同的签名,但最后一个参数在另一个参数中声明 为 Optional ,而 ParamArray 则编译器会根据最接近的匹配解析对该过程的调用。 有关详细信息,请参阅 重载解析。