【问题标题】:Can I pass a VBA module as an argument to a Sub/Function?我可以将 VBA 模块作为参数传递给子/函数吗?
【发布时间】:2019-08-07 14:32:49
【问题描述】:

我正在尝试重构一些 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

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

在 Sheet1 中:

Private Sub DoSomething()
    Set w = Worksheets(GROUP1_SHEET)
    'some code
End Sub

在 Sheet2 中:

Private Sub DoSomething()
    Set w = Worksheets(GROUP2_SHEET)
    'same code as above
End Sub

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

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

在新模块 GROUP1 中:

Public Property Get SHEET() As String
    SHEET = "Sheet1"
End Property

这可以按我的意愿工作:

Public Sub ShowPopup()
    MsgBox GROUP1.SHEET
End Sub

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

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

Public Sub ShowPopUp()
    Popup GROUP1
End Sub

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

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

【问题讨论】:

标签: excel vba


【解决方案1】:

您不能将常规模块作为参数传递(从技术上讲,您可以传递一个字符串并使用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

那么你可以这样使用它:

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 

我使用Private TypePrivate This as TypeGroup can be found here 的原因。类实例化的一些注意事项可以是seen here。根据您的工作,您的班级组织可能会非常不同。您可以在其他地方阅读接口、不变性、何时使用 getter/setter、封装和其他主题。

【讨论】:

  • 谢谢。我试图在这个重构工作中坚持一种轻巧的方法,只是重新组织~850 个全局常量并简化/通用函数。我意识到这不合适,但我应该更快地完成,并且原作者和其他用户更容易遵循这种方式。希望这样也能更容易地清除我们看到的一些奇怪行为。至少是这样的计划......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
相关资源
最近更新 更多