我应该在VB / VBA中使用Call关键字吗?

时间:2010-04-04 04:48:38

标签: vb.net vba vb6 call

我在VB / VBA中调用subs时使用Call关键字。我知道这是可选的,但是使用它还是不让它更好?我一直认为它更明确,但也许只是噪音。

另外,我在另一个论坛上看到这个:使用Call关键字更快,因为它知道它不会返回任何值,因此它不需要设置任何堆栈空间来为返回值。

9 个答案:

答案 0 :(得分:25)

啊哈哈。我一直想知道这个,甚至在VBA上读一本两英寸厚的书基本上都说不要使用它,除非你想使用VBE的查找功能轻松找到大型项目中的电话。 / p>

但我刚刚找到另一种用途。

我们知道可以用冒号字符连接代码行,例如:

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

使用调用语句可以在维护代码缩进的同时连接过程调用:

Function Test()
    Call Function1 : Call Function2
End Function

如果您不使用上例中的调用语句,VBE将假定“Function1”是一个标签,并在代码窗口中保持对齐,即使它不会导致错误。

答案 1 :(得分:11)

对于VB6,如果有可能将其转换为VB.NET,则使用Call表示语法不会更改。 (在VB.NET中需要使用括号进行方法调用。)(我个人认为这不值得 - 任何.NET转换器至少能够在需要时放入括号。我只是将其列为一个原因。)

否则它只是语法糖。

注意Call关键字在调用其他方法/函数时可能不会更快,因为函数无论如何都返回它的值,并且VB不需要创建一个局部变量来接收它,即使{ <1}}未使用。

答案 2 :(得分:9)

我总是在VBA中使用Call。对我来说,它看起来更干净。但是,我同意,这只是语法糖,这正是个人偏好的范畴。在过去的几年里,我遇到了大约十几个全职VBA球员,其中没有一个人使用Call。这有一个额外的好处,我总是知道哪些代码是我的。 :P

答案 3 :(得分:4)

不,它只会在每次通话时添加7个字符而没有任何好处。

答案 4 :(得分:3)

我使用Call来完成我可能在VB.NET中使用的公共库函数的所有VBA开发。这允许我在VB的所有风格之间使用复制和粘贴来移动代码。我这样做是为了避免代码编辑器在“格式化”或“漂亮打印”粘贴代码时创建的语法错误。唯一的修改通常是Set语句包含/排除。

如果您没有计划将VB / VBA代码移动到VB.NET,则无需使用Call语句。

答案 5 :(得分:1)

如果您阅读MSDN Support page for the Call Statement,至少针对VBA的具体案例,它确实说致电是可选的,但是它与此非常相关,似乎没有人注意到这是引用的行:

  

如果使用Call语法调用任何内部函数或用户定义函数,则函数的返回值将被丢弃。

这就是通话远非无用的原因。假设您正在编写Sub SupportTasks ,它为您做了很多非常相关的事情 Main Subs(例如,它从文件中导入数据以供不同的程序使用) 。现在,请注意,由于 SupportTasks 正在读取外部数据,因此总是很有可能这些数据不会成为标准,而sub将无法履行其职责。 你做什么?

例如,如果出现问题,您可以使用返回 False 的布尔函数。而不是调用sub,而是在内部调用函数 SupportTasks ,如果存在异常,则 If 语句将退出Main子函数:

If Not SupportTasks(SomeArgument) Then
    Application.ScreenUpdating = True
    Exit Sub
'Else continue the Main sub regularly without writing anything in here
End If

如果您想知道这与致电有什么关系,请考虑以下事项:在另一个子系统中,我调用 SupportTasks ,但我不需要它返回布尔值(例如,我确定不会发生错误)。好吧,如果我没有将它放在 If 语句中或将函数分配给无用的变量,VBA将无法编译并返回错误(过程调用无效blah blah blah必须分配对某事的价值等等等等等等。那就是致电来节省一天的时间!

Call SupportTasks(SomeArgument) '<< "Call Function" call doesn't return an error

如果你仍然认为它毫无用处,可以把它当作一种保持井井有条的资源。为许多过程共享的例程编写单独的过程会使您的代码更短更易于理解,特别是在您编写非常大的应用程序时。例如,如果您的IT部门在交付/实施真实系统方面进展缓慢,那么使用Excel-Access集成构建的ERP可以更容易操作,修复和定制......

总结一下,互联网的一些智慧:

  

总是写下你的代码,好像将要审查它的人是一个知道你住在哪里的凶残的精神病患者。

阿门。

答案 6 :(得分:1)

我已经晚了7年,但几分钟之前,我刚刚在MSDN上阅读了一些内容时碰到了Call关键字。特别是,它被用来做我认为在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

答案 7 :(得分:1)

我发现“呼叫”的唯一情况是有用的,这是一个非常偶然的事情,关于一些特殊的操作员。

Dim c As IAsyncOperation(Of StartupTask) = StartupTask.GetAsync("Startup")
……
(Await c).Disable()

第二行出现了语法错误,就像你使用“新”运算符一样。我真的不想要一个新变量,这对我来说太不优雅了。所以我试过了:

DirectCast(Await c, StartupTask).Disable()

这在语法上是正确的。但后来IDE提醒我,“DirectCast”是不必要的并且简化了。是的,那就是:

Call (Await c).Disable()

这就是我喜欢VS2017预览的原因。

答案 8 :(得分:1)

没有人涵盖这一重要区别:在某些(常见)情况下,Call阻止函数(和子)参数周围的括号导致参数严格解释为ByVal。

对您来说,最大的收获是,如果确实在例程的参数周围使用了括号,即使不是必需的,也可能是死记硬背或习惯了,那么您应该使用Call来确保例程的隐式或显式ByRef不存在无视ByVal;或者,相反,您应该使用返回值的“等号”分配来避免无视(在这种情况下,您将不使用Call)。

同样,这是为了防止您从例程中获取ByVal不利。相反,当然,如果无论例程的声明如何,都希望通过ByVal进行解释,则不要使用Call(并使用括号)。

理论上:总结https://msdn.microsoft.com/en-us/library/ee478101%28v=vs.84%29.aspx “ ByRef和ByVal参数”

如果
1.分配了一个函数调用retval。 g。
    iSum = myfunc(myArg)

2.使用“呼叫”,例如。 g。
    致电myFunc(myArg)
    或
    打电话给mySub(myArg)

然后,括号严格划定调用参数列表;例程声明确定ByVal或ByRef。否则,括号会强制例程使用ByVal-即使在例程中未指定ByVal。因此,
    mySub(myArg)'使用ByVal而不考虑例程的声明

    使用ByRef调用mySub(myArg)',除非例程声明ByVal

还请注意,Call在语法上强制使用括号。你可以去
mySub myArg
但你不能去
叫mySub myArg
但是你可以去
致电mySub(myArg)
(并且在语法上必须加上括号才能分配功能返回值)

但是请注意,例程声明上的ByVal会覆盖所有这些。仅供参考,如果您保持沉默,ByRef总是隐含在声明中;因此,TMK ByRef除了记录片外没有其他价值。

从上面重复:对您来说,最大的收获是,如果确实在例程的参数周围使用了括号,即使不是必需的,也可能是死记硬背或习惯了,那么您应该使用Call来确保例程的隐式或显式ByRef不受ByVal的支持;或者,相反,您应该使用返回值的“等号”分配来避免无视(在这种情况下,您将不使用Call)。

同样,这是为了防止您从例程中获取ByVal不利。相反,当然,如果无论例程的声明如何,都希望通过ByVal进行解释,则不要使用Call(并使用括号)。