通话关键字-是否已弃用

时间:2019-06-08 08:06:37

标签: vba

documentation page

随着时间的流逝,我已经看到人们提到通话声明已过时,但我似乎找不到任何官方证据来支持这一说法。

在{{3}}上,页面的最新更新是( 12/03/2018 ),所以不能说是过时的信息。

大多数时候,我一直在代码中使用Call,仅仅是因为我发现了这一点:

Call function(arg1, arg2, arg3) 比...更具可读性 function arg1, arg2, arg3

现在要提出问题,任何人都可以提供一些见解来说明为什么我不应该再使用Call语句了吗?如果您确实不赞成使用,请提供指向资源的链接。

如果此问题违反了网站规则,请告诉我,我会很乐意将其删除,尽管很高兴得到答复。

3 个答案:

答案 0 :(得分:15)

一致性是国王

无论您呼叫Sub还是Function都没有任何区别。重要的是一致性,而这就是Call爱好者使用关键字带来的。与是否在参数列表周围加括号保持一致。

因此,代替此简单获取隐式调用语句:

MsgBox "I'm a function but you're discarding my return value, so no parentheses."

我们得到这样的东西:

MsgBox ("I'm a function but you're discarding my return value, and this call looks weird.")

我还没有看到Call实际上是 与任何类型的实际一致性 一起使用:

Call MsgBox("I'm a function but you're discarding my return value, so I have a Call keyword.")
Call MyProcedure(42)
Call ActiveSheet.Range("A1:A10").Clear
Call Beep
Call CallByName(obj, "SomeMethod", VbCalType.VbMethod)

一贯使用,Call很快变得令人讨厌,明显多余,并且放慢了阅读速度,因为眼睛不由自主地停下了关键词,然后大脑开始“哦嘿,小心,我们在这里打电话。”我想您一会儿就停止看到它了,只是感觉好像丢失了东西。

绝大多数每个单个可执行语句都将以某种抽象级别调用某个地方的某个东西-持续使用Call会使该语言比它更笨重已经是

除非Call并不是真正的一致性,否则更多的是能够轻松查看我自己的用户过程调用 ...这是只是抓住稻草使合法的古老构造合法化,这毫无用处: Call关键字没有合法用途

这是唯一的“合法”用例:

Public Sub Test()
DoSomething: DoSomethingElse
'vs.
'Call DoSomething: Call DoSomethingElse
End Sub

Private Sub DoSomething() '<~ dead code. can you see why?
End Sub

Private Sub DoSomethingElse()
End Sub

Call关键字将LineLabel:ParameterlessProcedureCall以及后面的:指令分隔符区分开。唯一的问题是,:指令分隔符非常适合在一行代码中打入和塞满尽可能多的可执行代码……它们对于可读性很糟糕。此外,每个人都同意,NEWLINE应该以任何以分号结尾的语言跟随;,尽管尽管编译器忽略行跳转是很有意义的

我们编写代码供人们阅读和维护,而不仅仅是供编译器构建和运行。


已弃用?说谁?

me and my ducky

我100%可以肯定,我一生中曾经读过Official docs,但该关键字已过时。哎呀,甚至是specified as being redundant。语言不断发展,VBA也不例外-即使具有令人难以置信的令人难以置信的水平向后兼容性,并且在二十年后没有任何重大变化,语言-甚至它的实践仍然很流畅,即使其维护者已退休发誓要随便

Call并不是VBA中唯一被弃用的令牌,但是出于可疑的主观原因,与本世纪人们用来证明坚持the formidable mistake that Systems Hungarian notation was的理由不相上下,它的根源很深。

Rem评论标记的捍卫者在哪里?为什么While...Wend仍然是Do While...Loop的替代品?是否有人通过Error语句而不是通过Err.Raise引发错误?使用Error$而不是通过Err.Description输出错误消息?用清晰易懂的$&%^!#类型提示声明变量类型?谁写On Local Error?为什么将Global用于真正的Public

如果显式Call并没有过时并且“使代码更具可读性”,那么为什么同一个人不使用显式Let语句进行值赋值以实现完全相同的显性/明晰度原因?

我认为现在已经是重写最佳实践的时候了,过去Call以及Let,匈牙利表示法和程序顶部的声明墙都过去了。每个编程社区都已经做到了这一点-只有VBA社区仍在坚持30年前的“最佳实践”,以获取全新的代码,而不仅仅是另一个时代编写的遗留代码。我怀疑VBA's "dread score"很有可能与这有很大关系,即使不考虑裸露的IDE。

我很希望能够从Microsoft MVP老朋友罗伯·博维(Rob Bovey)和史蒂芬·布伦(Stephen Bullen)那里获得引用,并说:“在这里,请参阅第172页,它说 call关键字已过时 ”({this answer似乎提到“关于VBA的两英寸厚的书,基本上说不要使用它,除非您想使用VBE的“查找”功能轻松地在大型项目中查找呼叫”),所以这可能是它,但是在任何时候,这些专家本质上都定义了最佳实践,“重构”是一个外来词,“单元测试”是一个极限编程疯狂的想法-整个编程领域都有在过去的20年中发生了巨大的变化,但VBA停滞不前。是时候结束这个了,继续前进。

谈到前进 ...

“使迁移到VB.NET更容易”

据称,使用Call语句可以更轻松地将代码移植到.NET,因为VB.NET将在任何地方都需要括号。恭喜,那是布洛克。首先,如果要真正 进行任何移植,则要移植的VBA代码不是VB.NET,而是很有可能是TypeScript。如果您手动复制VBA代码并对其进行“翻译”以使其能够以目标语言进行编译,则会很快发现不必处理括号是非常有限的事情,因为实际上其他所有内容都需要重写, ...包括丢弃 Call个令牌。

编写小型的,专门的程序,如果要做的事情不止一个,那么它们将执行很少的工作,利用抽象级别和类/对象,减少模块之间的耦合,提高内在的凝聚力。 >模块,并通过彻底的单元测试覆盖并记录了代码的行为, 可帮助您更快地移植VBA代码,并确保移植的代码工作相同。 Call和括号只是保持不良习惯的借口。

答案 1 :(得分:5)

由于以下原因,我尝试避免使用Call(因此对我而言已贬值)-在#VBA中,我考虑将括号中的变量作为超载标准ByVal的一种方式/ ByRef参数说明。我什么意思考虑以下示例:

Public Sub TestMe()

    Dim var1 As Long: var1 = 1
    Dim var2 As Long: var2 = 1

    IncrementByVal (var1)
    IncrementByRef (var2)

    Debug.Print var1, var2

End Sub

Public Function IncrementByVal(ByVal a As Variant) As Variant
    a = a + 100
    IncrementByVal = a
End Function

Public Function IncrementByRef(ByRef a As Variant) As Variant
    a = a + 100
    IncrementByRef= a
End Function

您可能会看到,var1var2都返回1,而var2应该是101,直到{{1 }}。 ByRef字的种类改善了VBA中的“功能”,但是当括号取代Call时(而不是括号时)以及在阅读代码时记住它变得太复杂了。因此,有3个案例是很多的:

ByRef

答案 2 :(得分:2)

重构代码或剪切不确定的新代码时,我经常使用Call。为了说明,使用Call需要在参数两边加上括号,从函数返回值也是如此。我可能想从函数返回值,或者我想通过引用传递参数(ByRef

Sub Test()
    Dim v

    '* Call requires brackets
    Call NotSureIfThisWillEndUpAsASubOrAFunction(1, 2)

    '* return a value from a Function then need brackets
    v = NotSureIfThisWillEndUpAsASubOrAFunction(1, 2)

    '* if always a sub then no brackets required
    WillAlwaysBeASub 4, 5

    '* but is this really so ugly, why deprecate this?
    Call WillAlwaysBeASub(4, 5)

End Sub

Function NotSureIfThisWillEndUpAsASubOrAFunction(a, b)

End Function

Sub WillAlwaysBeASub(c, d)

End Sub

编辑:我认为一直使用方括号(这意味着使用Call作为Subs的关键字)意味着花更少的时间在代码中跳出括号,然后在改变主意时将其放回原处。