模块在编写不占用大量内存的代码中扮演什么角色?

时间:2019-05-03 18:12:22

标签: vba

在工作中,我正在尝试进入VBA领域,尝试制作一个电子表格模板,该模板将在单击命令按钮时运行报告。

在某些情况下,我遇到了“内存不足”运行时错误,通过使用该网站上其他用户的建议组合来调试代码,可以轻松解决该错误!

但是,我现在对如何使代码减少内存密集性感到好奇。特别是,模块是否有助于减少代码的内存占用;如果是,那么在这方面应如何有效地使用它们?例如,我应该为每个模块分配一个Sub还是太过分了?

我是VBA的新手,所以欢迎您提供任何/所有帮助和批评!

1 个答案:

答案 0 :(得分:0)

简短的回答:什么也没有。


发生“内存不足”错误的原因很多,其中没有一个与组织代码的模块数量有关。因为所有模块都是:可供您使用的组织工具。

如果完全不知道代码在做什么,就完全不可能诊断出“内存不足”错误:<meta>您必须先将问题缩小到特定的特定代码段,然后再问在此网站上进行有关处理(转储整个模块并询问“此代码有什么问题吗?”将无法实现)</meta>

寻找非常大的数组,也许是剪贴板操作。也许您正在运行一个循环,尝试创建和存储成百上千的New个大对象-几乎可以是任何东西……而不仅仅是模块的数量。


  

我应该为每个模块分配一个Sub还是太过分了?

与许多事物一样,答案是“取决于”。一旦熟悉了该语言,并开始学习面向对象的编程(OOP),您就会发现强烈建议使公共接口保持简单的设计准则和原则:遵守 Interface隔离原则(“ SOLID”的“ I”)表示这是一个完全完整且可以接受的类模块,具有:

'@Interface IComparable
'@ModuleDescription("Defines a generalized type-specific comparison method that a class implements to order or sort its instances.")
Option Explicit

'@Description("Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes (-1), follows (1), or occurs in the same position in the sort order (0) as the other object.")
Public Function CompareTo(ByVal other As Object) As Integer
End Function

但这远远超出了初学者级过程编程概念。

  

[...],当单击命令按钮时,它将运行报告。

该命令按钮可以是ActiveX按钮,也可以是附加到宏的Shape对象。假设它是ActiveX,则工作表的代码可能如下所示:

Option Explicit

Private Sub RunSalesReportButton_Click()
    SalesReportMacro.CreateWeeklyReport
End Sub

然后您可以拥有一个SalesReportMacro标准模块,该模块可能会像这样开始:

'@ModuleDescription("A macro that generates the weekly sales report.")
Option Explicit
Option Private Module

'@Descrition("Generates the weekly sales report.")
Public Sub CreateWeeklyReport()
    If Not RefreshSalesData Then Exit Sub
    CreatePivotReport
End Sub

顶部的Public过程具有很高的抽象水平:很容易一眼就知道该过程将要做什么,因为较低层的过程具有有意义的名字告诉我们到底发生了什么。这些较低级别的程序将位于下面:

Private Function RefreshSalesData() As Boolean
    Dim reportWeek As String
    reportWeek = PromptForReportWeek
    If Not IsNumeric(reportWeek) Then Exit Function

    On Error GoTo CleanFail
    AdjustDataConnectionCommand reportWeek
    RefreshSalesData = True

CleanExit:
    Exit Function
CleanFail:
    MsgBox "Could not refresh the data for week " & reportWeek & ".", vbExclamation
    Resume CleanExit
End Function

越深入,抽象度就越低:

Private Function PromptForReportWeek() As String
    Dim currentWeek As Integer
    currentWeek = GetCurrentWeekNumber
    PromptForReportWeek = InputBox("Please specify week#", "Generate Report", currentWeek)
End Function

Private Function GetCurrentWeekNumber()
    GetCurrentWeekNumber = 42 'todo
End Function

Private Sub AdjustDataConnectionCommand(ByVal weekNumber As String)
    With ThisWorkbook.Connections(1).OLEDBConnection
        .CommandText = "dbo.WeeklySalesReport " & weekNumber
        .Refresh
    End With
End Sub

Private Sub CreatePivotReport()
    'todo
End Sub

过程(SubFunction,以及您将在适当的时候发现的其他过程)应具有一个目的,并保持简短并专注于一项任务尽可能。这样一来,您可以更轻松地稍后重新解析代码。例如,您需要在2个月内为新的CreateWeeklyInventoryReport宏添加另一个ActiveX按钮:此新报告很有可能会还需要PromptForReportWeek-如果该功能已经很好地抽象到了它自己的范围内,则可以更轻松地从该模块中删除/剪切该功能,添加一个新的CalendarParameterPrompt模块(该模块...可能只需要一段时间那个过程即可..直到您需要一个放置类似PromptForReportMonth函数的好地方),在其中添加/粘贴,使其成为{{1} },然后从其他任何宏/模块中调用它。

执行此操作,而不是执行一事无成的大规模万能程序(最终由于它们太大而导致VBA拒绝编译,因此最终停止编译),这将使您在不久的将来免于很多麻烦