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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2573597/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 10:21:47  来源:igfitidea点击:

Should I use Call keyword in VB/VBA?

vb.netvbavb6call

提问by Fred Loyant

I use the Callkeyword when calling subs in VB/VBA. I know it's optional, but is it better to use it or leave it off? I've always thought it was more explicit, but maybe it's just noise.

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

Also, I read this on another forum: Using the Callkeyword is faster because it knows that it is not going to return any values, so it doesn't need to set up any stackspace to make room for the return value.

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

回答by Jamie Garroch

Ah ha. I have long wondered about this and even reading a two inch thick book on VBA basically says don't use it unless you want to use the Findfeature of the VBE to easily find calls in large projects.

啊哈。我一直想知道这个问题,甚至阅读一本两英寸厚的关于 VBA 的书基本上都说不要使用它,除非您想使用VBE的查找功能轻松查找大型项目中的调用。

But I just found another use.

但我刚刚发现了另一个用途。

We know that it's possible to concatenate lines of code with the colon character, for example:

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

Function Test(mode as Boolean) 
    if mode = True then x = x + 1 : Exit Sub
    y = y - 1
End Sub

But if you do this with procedure calls at the beginning of a line, the VBE assumes that you're referring to a label and removes any indents, aligning the line to the left margin (even though the procedure is called as intended):

但是,如果您在一行的开头对过程调用执行此操作,则 VBE 假定您指的是一个标签并删除任何缩进,将行与左边距对齐(即使该过程按预期调用):

Function Test()
Function1 : Function2
End Function

Using the Callstatement allows concatenation of procedure calls while maintaining your code indents:

使用Call语句允许在保持代码缩进的同时串联过程调用:

Function Test()
    Call Function1 : Call Function2
End Function

If you don't use the Callstatement in the above example, the VBE will assume that "Function1" is an label and left align it in the code window, even though it won't cause an error.

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

回答by Mark Hurd

For VB6, if there is any chance it will be converted to VB.NET, using Callmeans the syntax doesn't change. (Parentheses are required in VB.NET for method calls.) (I don't personally think this is worth the bother -- any .NET converter will at least be able to put in parentheses when required. I'm just listing it as a reason.)

对于 VB6,如果有任何机会将其转换为 VB.NET,使用Call意味着语法不会改变。(在 VB.NET 中需要括号用于方法调用。)(我个人认为这不值得麻烦——任何 .NET 转换器至少可以在需要时放入括号。我只是将它列为一个原因。)

Otherwise it is just syntactic sugar.

否则它只是语法糖。

Note the Callkeyword is likely not to be faster when calling some other method/function because a function returns its value anyway, and VB didn't need to create a local variable to receive it, even when Callis not used.

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

回答by Nick Spreitzer

I always use Callin VBA. To me, it just looks cleaner. But, I agree, it's just syntactic sugar, which puts it squarely the realm of personal preference. I've come across probably a dozen full time VBA guys in the past few years, and not one of them used Call. This had the added advantage that I always knew which code was mine. :p

我总是Call在 VBA 中使用。对我来说,它看起来更干净。但是,我同意,这只是语法糖,这完全符合个人喜好。在过去的几年里,我可能遇到过十几个全职 VBA 人员,但他们中没有一个使用Call. 这有一个额外的好处,我总是知道哪个代码是我的。:p

回答by svinto

No, it'll just add 7 characters per call with no given benefit.

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

回答by AMissico

I use Callfor all VBA development of common library functions that I possibly will use in VB.NET. This allows me to move code using copy and paste between all the flavors of VB. I do this to avoid the syntax errors that the code editor creates when it "formats" or "pretty prints" the pasted code. The only edits are usually Setstatement inclusion/exclusion.

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

If you have no plans to move your VB/VBA code to VB.NET, then there is no need to use the Callstatement.

如果您不打算将 VB/VBA 代码移动到 VB.NET,则无需使用该Call语句。

回答by MicrosoftShouldBeKickedInNuts

No one covered this important distinction: in some (common) situations, Call prevents parentheses around function (and sub) arguments from causing the arguments to be strictly interpreted as ByVal.

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

The big takeaway for you is that if you DO use parentheses around arguments to a routine, perhaps by rote or habit, even though they are not required, then you SHOULD USE Callto ensure that the routine's implicit or explicit ByRefis not disregarded in favor of ByVal; or, instead, you should use an "equal sign" assignment of the return value to prevent the disregard (in which case you would not use Call).

对您来说最重要的一点是,如果您确实在例程的参数周围使用括号,可能是死记硬背或习惯,即使它们不是必需的,那么您应该使用Call以确保例程的隐式或显式ByRef不会被忽视而有利于ByVal; 或者,您应该使用返回值的“等号”分配来防止忽略(在这种情况下您不会使用Call)。

Again, that is to protect you from unfavorably getting ByValfrom a routine. Conversely, of course, if you WANT ByValinterpretation regardless of the routine's declaration, then LEAVE OFF the Call(and use parentheses).

同样,那是为了保护您免受ByVal例行公事的不利影响。相反,当然,如果您想要ByVal解释而不考虑例程的声明,那么请离开Call(并使用括号)。

Rationale: summarizing "ByRef and ByVal Parameters"

基本原理:总结“ByRef 和 ByVal 参数”

If
1. there is an assignment of a function call retval, e. g.

如果
1. 有一个函数调用 retval 的赋值,例如

iSum = myfunc(myArg)  

or
2. "Call" is used, e. g.


2. 使用“ Call”,例如

call myFunc(myArg)  

or

或者

call mySub(myArg)

then the parentheses strictly delineate the calling argument list; the routine declaration determines ByVal or ByRef. OTHERWISE the parentheses force ByVal to be used by the routine - even though ByVal was not specified in the routine. Thus,

然后括号严格地描述了调用参数列表;例程声明确定 ByVal 或 ByRef。否则,括号强制例程使用 ByVal - 即使例程中未指定 ByVal。因此,

    mySub(myArg)       'uses ByVal regardless of the routine's declaration, whereas  
    Call mySub(myArg)  'uses ByRef, unless routine declares ByVal

Also note that Call syntactically mandates use of parentheses. You can go

另请注意,Call 在语法上要求使用括号。你可以走了

mySub myArg  

but you can't go

但你不能去

call mySub myArg  

but you CAN go

但你可以去

call mySub(myArg)  

(and parentheses are syntactically required for assignment of Function return value)

(在语法上需要括号来分配函数返回值)

NOTE however that ByValon the routine declaration overrides all of this. And FYI, ByRefis always implied in the declaration if you are silent; thus TMK ByRefhas no apparent value other than documentary.

但是请注意,ByVal例程声明会覆盖所有这些。仅供参考,ByRef如果您保持沉默,声明中总是暗示;因此,TMKByRef除了纪录片之外没有任何明显的价值。

Repeating from above: The big takeaway for you is that if you DO use parentheses around arguments to a routine, perhaps by rote or habit, even though they are not required, then you SHOULD USE Callto ensure that the routine's implicit or explicit ByRefis not disregarded in favor of ByVal; or, instead, you should use an "equal sign" assignment of the return value to prevent the disregard (in which case you would not use Call).

从上面重复:对你来说最大的收获是,如果你确实在例程的参数周围使用括号,也许是死记硬背或习惯,即使它们不是必需的,那么你应该使用Call以确保例程的隐式或显式ByRef不被忽视赞成ByVal;或者,您应该使用返回值的“等号”分配来防止忽略(在这种情况下您不会使用Call)。

Again, that is to protect you from unfavorably getting ByValfrom a routine. Conversely, of course, if you WANT ByValinterpretation regardless of the routine's declaration, then LEAVE OFF the Call(and use parentheses).

同样,那是为了保护您免受ByVal例行公事的不利影响。相反,当然,如果您想要ByVal解释而不考虑例程的声明,那么请离开Call(并使用括号)。

回答by FCastro

If you read the MSDN Support page for the Call Statement, for the specific case o VBA, at least, it does say that Callis optional, but what is very relevant about it and nobody seems to notice is this quoted line:

如果您阅读了Call StatementMSDN 支持页面,至少对于 VBA 的特定情况,它确实说Call是可选的,但是与它非常相关并且似乎没有人注意到以下引用的行:

"If you use either Call syntax to call any intrinsic or user-defined function, the function's return value is discarded."

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

This is why Callis far from useless. Say you're writing Sub SupportTasksthat does a lot of very relevant stuff for you MainSubs (for example, it imports data from a file to be used by different procedures). Now, notice that since SupportTasksis reading external data, there's always a fat chance this data will not come standard and the sub will not be able to fulfill its role. What do you do?

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

You could, for example, use boolean functions that return Falseif something goes wrong. Instead of calling a sub, call a function SupportTasksinside and Ifstatement that will exit the Main sub if there's an anomaly:

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

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

If you're wondering what the heck this has to do with Call, consider the following: in another sub, I call SupportTasks, but I do not need its returned boolean value (for instance, I'm certain an error won't occur). Well, if I don't put it in an Ifstatement or assign the function to a useless variable, VBA will not compile and return me an error (procedure call invalid blah blah blah must assign value to something blah blah blah). That's where Callcomes in to save the day!

如果您想知道这与Call有什么关系,请考虑以下事项:在另一个子程序中,我调用SupportTasks,但我不需要它返回的布尔值(例如,我确定不会发生错误)。好吧,如果我不把它放在If语句中或将函数分配给一个无用的变量,VBA 将不会编译并返回一个错误(过程调用无效等等等等必须为某些东西赋值等等等等)。这就是Call 的用武之地!

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

If you still think it's useless, think of it as a resource to stay organized. Writing separate procedures for routines shared by many procedures makes your code shorterand more comprehensible, specially when you're writing really large applications. ERPs built out of Excel-Access integrations, for example, can be easier to operate, repair and customize if your IT dept slow to deliver/implement the real system...

如果您仍然认为它没有用,请将其视为保持井井有条的资源。编写单独的程序被许多程序共享程序使你的代码更短更容易理解,特别是当你写真正大的应用程序。例如,如果您的 IT 部门交付/实施真实系统的速度缓慢,那么基于 Excel-Access 集成构建的 ERP 可以更容易操作、修复和定制...

To conclude, some internet wisdom:

总而言之,一些互联网智慧:

Always write your code as if the person who will review it is a murderous psychopath who knows where you live.

始终编​​写您的代码,就好像它的人是一个知道您住在哪里的凶残的精神病患者一样。

Amen.

阿门。

回答by Brandon Hood

I'm 7 years late to the party, but I just happened to come across the Callkeyword a few minutes ago while reading something on MSDN. In particular, it was used to do something I thought was impossible in VB.NET (as opposed to C#) -- which is related to @FCastro's answer.

我参加聚会晚了 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

In the odd case you don't need the actual object instance but require one of its methods, you can use Callto save a line. Note that this is unnecessary when it's the right-hand side of an operation:

在奇怪的情况下,您不需要实际的对象实例但需要其方法之一,您可以使用它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

回答by u8789984

The only case I found "call" is useful is quite an accident, about some special operators.

我发现“调用”有用的唯一情况是非常偶然的,关于一些特殊的操作符。

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

I got a syntax error for the second line, just like what you'll get with a "New" operator. I really don't want a new variable, which is too inelegant for me. So I tried:

我在第二行遇到语法错误,就像使用“New”运算符会得到的结果一样。我真的不想要一个新变量,这对我来说太不雅了。所以我试过:

DirectCast(Await c, StartupTask).Disable()

This is syntactically correct. But then the IDE hinted me that the "DirectCast" is unnecessary and gave a simplification. Yes, that is:

这在语法上是正确的。但随后 IDE 提示我“DirectCast”是不必要的,并进行了简化。对,是:

Call (Await c).Disable()

That's why I love VS2017 Preview.

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