簡體   English   中英

我應該在 VB/VBA 中使用 Call 關鍵字嗎?

[英]Should I use Call keyword in VB/VBA?

我在 VB/VBA 中調用 subs 時使用Call關鍵字。 我知道它是可選的,但是使用它還是放棄它更好? 我一直認為它更明確,但也許這只是噪音。

另外,我在另一個論壇上讀到:使用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,使用Call意味着語法不會改變。 (在 VB.NET 中需要括號用於方法調用。)(我個人認為這不值得麻煩——任何 .NET 轉換器至少可以在需要時放入括號。我只是將它列為一個原因。)

否則它只是語法糖。

請注意, Call其他方法/函數時, Call關鍵字可能不會更快,因為函數無論如何都會返回其值,並且即使不使用Call ,VB 也不需要創建局部變量來接收它。

我總是在 VBA 中使用Call 對我來說,它看起來更干凈。 但是,我同意,這只是語法糖,這完全符合個人喜好。 在過去的幾年里,我可能遇到過十幾個全職 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總是隱含在聲明中; 因此,TMK ByRef除了紀錄片之外沒有明顯的價值。

從上面重復:對你來說最大的收獲是,如果你確實在例程的參數周圍使用括號,可能是死記硬背或習慣,即使它們不是必需的,那么你應該使用Call來確保例程的隱式或顯式ByRef是沒有被忽視而有利於ByVal 或者,您應該使用返回值的“等號”分配來防止忽略(在這種情況下您不會使用Call )。

同樣,這是為了保護您免於從例程中不利地獲得ByVal 相反,當然,如果您想要ByVal解釋而不管例程的聲明,那么請離開Call (並使用括號)。

如果您閱讀了Call StatementMSDN 支持頁面,至少對於 VBA 的特定情況,它確實說Call是可選的,但是與它非常相關並且似乎沒有人注意到以下引用的行:

"如果您使用 Call 語法來調用任何內部函數或用戶定義函數,則該函數的返回值將被丟棄。 "

這就是Call遠非無用的原因。 假設您正在編寫 Sub SupportTasks ,它為您的Main Subs 做了很多非常相關的事情(例如,它從文件中導入數據以供不同的過程使用)。 現在,請注意,由於SupportTasks正在讀取外部數據,因此這些數據很可能不符合標准並且 sub 將無法履行其職責。 你做什么工作?

例如,您可以使用在出現問題時返回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

如果您想知道這與Call有什么關系,請考慮以下事項:在另一個子程序中,我調用SupportTasks ,但我不需要它返回的布爾值(例如,我確定不會發生錯誤)。 好吧,如果我不把它放在If語句中或將函數分配給一個無用的變量,VBA 將不會編譯並返回一個錯誤(過程調用無效等等等等必須為某些東西賦值等等等等)。 這就是Call 的用武之地!

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

如果您仍然認為它沒有用,請將其視為保持井井有條的資源。 為許多過程共享的例程編寫單獨的過程可以使您的代碼更短且更易於理解,尤其是在您編寫非常大的應用程序時。 例如,如果您的 IT 部門交付/實施真實系統的速度緩慢,則基於 Excel-Access 集成構建的 ERP 可以更輕松地操作、修復和定制...

總而言之,一些互聯網智慧:

始終編​​寫您的代碼,就好像審查它的人是一個知道您住在哪里的凶殘的精神病患者一樣。

阿門。

我參加聚會晚了 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

我發現“調用”有用的唯一情況是非常偶然的,關於一些特殊的操作符。

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 預覽版的原因。 😄

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM