在工作中,我正在尝试进入VBA领域,尝试制作一个电子表格模板,该模板将在单击命令按钮时运行报告。
在某些情况下,我遇到了“内存不足”运行时错误,通过使用该网站上其他用户的建议组合来调试代码,可以轻松解决该错误!
但是,我现在对如何使代码减少内存密集性感到好奇。特别是,模块是否有助于减少代码的内存占用;如果是,那么在这方面应如何有效地使用它们?例如,我应该为每个模块分配一个Sub
还是太过分了?
我是VBA的新手,所以欢迎您提供任何/所有帮助和批评!
答案 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
过程(Sub
,Function
,以及您将在适当的时候发现的其他过程)应具有一个目的,并保持简短并专注于一项任务尽可能。这样一来,您可以更轻松地稍后重新解析代码。例如,您需要在2个月内为新的CreateWeeklyInventoryReport
宏添加另一个ActiveX按钮:此新报告很有可能会还需要PromptForReportWeek
-如果该功能已经很好地抽象到了它自己的范围内,则可以更轻松地从该模块中删除/剪切该功能,添加一个新的CalendarParameterPrompt
模块(该模块...可能只需要一段时间那个过程即可..直到您需要一个放置类似PromptForReportMonth
函数的好地方),在其中添加/粘贴,使其成为{{1} },然后从其他任何宏/模块中调用它。
执行此操作,而不是执行一事无成的大规模万能程序(最终由于它们太大而导致VBA拒绝编译,因此最终停止编译),这将使您在不久的将来免于很多麻烦