Visual Basic跨多Sub的Goto替代方案优化咨询
Great question—using global variables for this kind of flow control does get messy quickly, and there are cleaner, more maintainable ways to handle this without relying on shared state. Here are a couple of solid approaches:
1. Use a Function with a Boolean Return Value
Instead of a global flag, turn your Case_DatatoGet subroutine into a function that returns a Boolean indicating whether the calling procedure should continue executing its remaining steps. This keeps the control signal encapsulated and avoids global state.
Sub btnRun_Click() Handles btnRun.Click ChooseSaveLocation() ' Only proceed with the final steps if Case_DatatoGet returns True If Case_DatatoGet(DatatoGet:=cmb_DatatoRetrieve.Text) Then WriteDatatoDestination(datachoice:=cmb_DatatoRetrieve.SelectedItem, Destination:=cmb_Destination.SelectedItem) Debug.Print("---------------Finished with Run----------------") End If End Sub ' Convert to a Function that returns True/False based on validation Function Case_DatatoGet(DatatoGet As String) As Boolean If DatatoGet = "" Then MsgBox("Please click on settings and choose data to retrieve") Return False ' Signal calling procedure to stop here Else Select Case DatatoGet Case "Company Info" GetCompanyInfo(txt_APIUsername.Text, txt_APIPassword.Text) Case "Prices" GetPrices(txt_APIUsername.Text, txt_APIPassword.Text) Case "Balance Sheets" Debug.Print("Write a balance sheet sub") Case "Income Statements" Debug.Print("Write a Income Statement sub") Case "Statement of Cash Flows" Debug.Print("Write a Statement of Cash Flows sub") End Select Return True ' Signal calling procedure to continue End If End Function
2. Refactor Logic into Modular Subroutines
For more complex flows, split your code into smaller, focused subroutines. This makes the logic easier to follow and separates validation from execution.
Sub btnRun_Click() Handles btnRun.Click ChooseSaveLocation() ' Validate first; if valid, run the data get and finish up If IsDatatoGetValid(cmb_DatatoRetrieve.Text) Then Case_DatatoGet(DatatoGet:=cmb_DatatoRetrieve.Text) CompleteRun() End If End Sub ' Separate validation into its own function Function IsDatatoGetValid(DatatoGet As String) As Boolean If DatatoGet = "" Then MsgBox("Please click on settings and choose data to retrieve") Return False End If Return True End Function Sub Case_DatatoGet(DatatoGet As String) Select Case DatatoGet Case "Company Info" GetCompanyInfo(txt_APIUsername.Text, txt_APIPassword.Text) Case "Prices" GetPrices(txt_APIUsername.Text, txt_APIPassword.Text) Case "Balance Sheets" Debug.Print("Write a balance sheet sub") Case "Income Statements" Debug.Print("Write a Income Statement sub") Case "Statement of Cash Flows" Debug.Print("Write a Statement of Cash Flows sub") End Select End Sub ' Encapsulate the final steps in their own subroutine Sub CompleteRun() WriteDatatoDestination(datachoice:=cmb_DatatoRetrieve.SelectedItem, Destination:=cmb_Destination.SelectedItem) Debug.Print("---------------Finished with Run----------------") End Sub
Why These Are Better Than Global Variables
- No shared state: Global variables can be accidentally modified elsewhere in your code, leading to hard-to-debug bugs. Return values and modular logic keep control flow explicit.
- Readability: Anyone reading your code can immediately see what's controlling the flow, instead of having to track down a global variable's usage.
- Maintainability: These approaches make it easier to update or extend your logic later without breaking other parts of the code.
Avoid using exceptions for flow control—exceptions are meant for handling unexpected errors, not normal program flow, and they can hurt performance if overused.
内容的提问来源于stack exchange,提问作者ThomasRones

