我Call
在 VB/VBA 中调用 subs 时使用关键字。我知道它是可选的,但是使用它还是关闭它更好?我一直认为它更明确,但也许这只是噪音。
另外,我在另一个论坛上读到:使用Call
关键字更快,因为它知道它不会返回任何值,因此不需要设置任何堆栈空间来为返回值腾出空间。
啊哈。我一直想知道这一点,甚至阅读一本两英寸厚的关于 VBA 的书基本上都说不要使用它,除非您想使用 VBE 的查找功能轻松查找大型项目中的调用。
但我刚刚发现了另一种用途。
我们知道可以将代码行与冒号字符连接起来,例如:
Function Test(mode as Boolean)
if mode = True then x = x + 1 : Exit Sub
y = y - 1
End Sub
但是,如果您在行首使用过程调用执行此操作,VBE 会假定您指的是标签并删除任何缩进,将行与左边距对齐(即使按预期调用过程):
Function Test()
Function1 : Function2
End Function
使用Call语句可以在保持代码缩进的同时连接过程调用:
Function Test()
Call Function1 : Call Function2
End Function
如果您在上面的示例中不使用Call语句,VBE 将假定“Function1”是一个标签并在代码窗口中左对齐,即使它不会导致错误。
对于 VB6,如果有可能将其转换为 VB.NET,则 usingCall
意味着语法不会改变。(在 VB.NET 中,方法调用需要括号。)(我个人认为这不值得费心——任何 .NET 转换器至少可以在需要时放入括号。我只是将其列为一个原因。)
否则它只是语法糖。
请注意,Call
在调用其他方法/函数时,关键字可能不会更快,因为函数无论如何都会返回其值,并且 VB 不需要创建局部变量来接收它,即使在Call
不使用时也是如此。
我总是Call
在 VBA 中使用。对我来说,它只是看起来更干净。但是,我同意,这只是句法糖,这完全是个人喜好的领域。在过去的几年里,我可能遇到过十几个全职的 VBA 人员,但没有一个人使用过Call
. 这有一个额外的好处,即我总是知道哪个代码是我的。:p
不,每次通话只会添加 7 个字符,没有任何好处。
我Call
用于所有可能会在 VB.NET 中使用的通用库函数的 VBA 开发。这允许我在所有 VB 风格之间使用复制和粘贴来移动代码。我这样做是为了避免代码编辑器在“格式化”或“漂亮打印”粘贴的代码时创建的语法错误。唯一的编辑通常是Set
语句包含/排除。
如果您没有计划将 VB/VBA 代码移至 VB.NET,则无需使用该Call
语句。
没有人涵盖这个重要的区别:在某些(常见)情况下, Call 防止函数(和子)参数周围的括号导致参数被严格解释为ByVal
.
对您来说最大的收获是,如果您确实在例程的参数周围使用括号,可能是死记硬背或习惯,即使它们不是必需的,那么您应该使用Call
以确保例程的隐式或显式ByRef
不会被忽视ByVal
;或者,您应该使用返回值的“等号”分配来防止忽略(在这种情况下,您不会使用Call
)。
再次,这是为了保护你免受不利ByVal
的日常生活。相反,当然,如果您想要ByVal
解释而不考虑例程的声明,那么请不要Call
使用(并使用括号)。
基本原理:总结“ByRef 和 ByVal 参数”
如果
1. 有一个函数调用 retval 的赋值,例如
iSum = myfunc(myArg)
或
2.Call
使用“”,例如
call myFunc(myArg)
或者
call mySub(myArg)
然后括号严格描述调用参数列表;例程声明确定 ByVal 或 ByRef。否则,括号会强制例程使用 ByVal - 即使例程中未指定 ByVal。因此,
mySub(myArg) 'uses ByVal regardless of the routine's declaration, whereas
Call mySub(myArg) 'uses ByRef, unless routine declares ByVal
另请注意, Call 在语法上要求使用括号。你可以走了
mySub myArg
但你不能去
call mySub myArg
但你可以去
call mySub(myArg)
(并且括号在语法上是分配函数返回值所必需的)
但是请注意,ByVal
在例程声明中会覆盖所有这些。仅供参考,ByRef
如果您保持沉默,则声明中始终暗示;因此,TMKByRef
除了纪录片之外没有任何明显的价值。
从上面重复:对您来说最大的收获是,如果您确实在例程的参数周围使用括号,可能是死记硬背或习惯,即使它们不是必需的,那么您应该使用Call
以确保例程的隐式或显式ByRef
不被忽视赞成ByVal
;或者,您应该使用返回值的“等号”分配来防止忽略(在这种情况下,您不会使用Call
)。
再次,这是为了保护你免受不利ByVal
的日常生活。相反,当然,如果您想要ByVal
解释而不考虑例程的声明,那么请不要Call
使用(并使用括号)。
我发现“呼叫”有用的唯一情况是相当偶然的,关于一些特殊的操作员。
Dim c As IAsyncOperation(Of StartupTask) = StartupTask.GetAsync("Startup")
……
(Await c).Disable()
第二行出现语法错误,就像使用“New”运算符一样。我真的不想要一个新变量,这对我来说太不优雅了。所以我尝试了:
DirectCast(Await c, StartupTask).Disable()
这在语法上是正确的。但随后 IDE 提示我“DirectCast”是不必要的,并进行了简化。对,是:
Call (Await c).Disable()
这就是我喜欢 VS2017 Preview 的原因。
如果您阅读了Call Statement 的 MSDN Support 页面,至少对于 VBA 的特定情况,它确实说Call是可选的,但是与它非常相关并且似乎没有人注意到的是这行引用的行:
"如果您使用 Call 语法来调用任何内部或用户定义的函数,则该函数的返回值将被丢弃。 "
这就是为什么Call远非无用的原因。假设您正在编写 Sub SupportTasks ,它为您的Main Subs做了很多非常相关的事情(例如,它从文件中导入数据以供不同的程序使用)。现在,请注意,由于SupportTasks正在读取外部数据,因此这些数据很可能不会成为标准,并且 sub 将无法履行其职责。你做什么工作?
例如,如果出现问题,您可以使用返回False的布尔函数。与其调用子程序,不如调用内部的函数SupportTasks和If语句,如果出现异常,该语句将退出主子程序:
If Not SupportTasks(SomeArgument) Then
Application.ScreenUpdating = True
Exit Sub
'Else continue the Main sub regularly without writing anything in here
End If
如果您想知道这与Call有什么关系,请考虑以下内容:在另一个子程序中,我调用SupportTasks,但我不需要它返回的布尔值(例如,我确定不会发生错误)。好吧,如果我不将它放在If语句中或将函数分配给无用的变量,VBA 将不会编译并返回错误(过程调用无效等等等等必须为某些东西赋值等等等等)。这就是呼叫进来拯救一天的地方!
Call SupportTasks(SomeArgument) '<< "Call Function" call doesn't return an error
如果您仍然认为它没用,请将其视为保持井井有条的资源。为许多过程共享的例程编写单独的过程可以使您的代码更短、更易于理解,特别是在您编写非常大的应用程序时。例如,如果您的 IT 部门交付/实施真实系统的速度较慢,则基于 Excel-Access 集成构建的 ERP 可以更易于操作、修复和定制……
最后,一些互联网智慧:
总是写你的代码,就好像审查它的人是一个知道你住在哪里的凶残的精神病患者。
阿门。
我迟到了 7 年,但Call
几分钟前我在 MSDN 上阅读某些内容时碰巧遇到了这个关键字。特别是,它被用来做我认为在 VB.NET(与 C# 相对)中不可能的事情——这与@FCastro 的回答有关。
Class Test
Public Sub DoSomething()
Console.WriteLine("doing something")
End Sub
End Class
Sub Main()
Call (New Test()).DoSomething()
End Sub
在奇怪的情况下,您不需要实际的对象实例但需要它的一种方法,您可以使用它Call
来保存一行。请注意,当它是操作的右侧时,这是不必要的:
Class Test
Public Function GetSomething() As Integer
Return 0
End Function
End Class
Sub Main()
Dim x As Integer = (New Test()).GetSomething()
End Sub