我可以将 VBA 模块作为参数传递给子/函数吗?

use*_*803 5 excel vba

我正在尝试重构一些 Excel VBA 代码(Excel 2016、VBA 7.1)以消除重复的子例程以实现可维护性。几个子例程的区别仅在于它们使用的全局常量组,所以我基本上想做的是将全局变量组合成一个类似结构的数据结构,这样我就可以将它们作为参数传递到一个公共函数中。

请注意,全局常量组有一些共同点,但不是全部,例如:

Global Const GROUP1_SHEET As String = "Sheet1"
Global Const GROUP1_FIRST_ROW As Long = 2
Global Const GROUP1_LAST_COL As Long = 15
Global Const GROUP1_SOME_COL_OFFSET = 4

Global Const GROUP2_SHEET As String = "Sheet2"
Global Const GROUP2_FIRST_ROW As Long = 2
Global Const GROUP2_LAST_COL As Long = 8
Global Const GROUP2_ANOTHER_COL_OFFSET = 2
Run Code Online (Sandbox Code Playgroud)

每组都有不同的子程序,例如:

在表 1 中:

Private Sub DoSomething()
    Set w = Worksheets(GROUP1_SHEET)
    'some code
End Sub
Run Code Online (Sandbox Code Playgroud)

在表2中:

Private Sub DoSomething()
    Set w = Worksheets(GROUP2_SHEET)
    'same code as above
End Sub
Run Code Online (Sandbox Code Playgroud)

有几十个这样的。不用说,这段代码连阅读起来都是一场噩梦,更不用说维护了。

我现在想做的是将组拆分为单独的模块并将它们设置为属性,类似于此问题中描述的内容。问题是我不知道如何将模块(即全局变量组)作为参数传递给函数。

在新模块 GROUP1 中:

Public Property Get SHEET() As String
    SHEET = "Sheet1"
End Property
Run Code Online (Sandbox Code Playgroud)

这按我想要的方式工作:

Public Sub ShowPopup()
    MsgBox GROUP1.SHEET
End Sub
Run Code Online (Sandbox Code Playgroud)

但将其作为参数传递并不:

Public Sub Popup(inModule As Object)
    MsgBox inModule.SHEET
End Sub

Public Sub ShowPopUp()
    Popup GROUP1
End Sub
Run Code Online (Sandbox Code Playgroud)

我尝试过的任何方法都无法代替上面示例中的“对象”。我要么得到“ByRef 参数类型不匹配”,要么得到“预期变量或过程,而不是模块”,具体取决于我放在那里的内容。

那么,我可以传递这样的模块(也许作为字符串并以某种方式对其进行评估?),还是应该使用其他某种方式对全局变量进行分组?

Vic*_*r K 4

您不能将常规模块作为参数传递(从技术上讲,您可以传递字符串并使用Application.Run,但这可能是一场噩梦),但您可以传递类。

类可以在全局范围内。因此从技术上讲,您可以在某个时刻实例化它(例如打开工作簿),然后在任何时刻使用它们。我想说,全局变量在某些情况下很好,但大多数时候你可以(也许应该)不用它们。我鼓励您研究全局范围的主题以及为什么它通常被认为是不好的。

你可以有这样的课程:

GroupClass:
Option Explicit
Private Type TypeGroup
    WS as WorkSheet
    FirstRow as Long
    FirstCol as Long
    ColumnOffset as Long
End Type
Private This as TypeGroup
Public Function Initialize(Byval WS as Sheet, Byval FirstRow as Long, ByVal FirstCol as Long, ByVal ColumnOffset as Long)
With This
    Set .WS = WS
    .FirstRow = FirstRow
    .FirstCol = FirscCol
    .ColumnOffset = ColumnOffset
End with
End Function
Public Property Get Name() as String
    Name = This.WS.Name
End Property
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

Public Sub Popup(Group As GroupClass)
    MsgBox Group.Name
End Sub

Public Sub ShowPopUp()
    Dim Group1 as GroupClass
    Set Group1 = New GroupClass
    Group1.Initialize Worksheets("Sheet1"),2,15,4
    Popup Group1
End 
Run Code Online (Sandbox Code Playgroud)

Private Type我使用和的原因Private This as TypeGroup 可以在这里找到。可以在此处看到有关类实例化的一些注意事项。根据您所做的事情,您的班级组织可能会非常不同。您可以在其他地方阅读接口、不变性、何时使用 getter/setter、封装和其他主题。