何时在VBA中使用类?
何时在VBA中使用类?
在Visual Basic for Applications (VBA)中何时适合使用类?
我假设加速开发和减少引入错误对于大多数支持OOP的语言来说都是一个常见的优点。但在VBA中,是否有特定的标准?
当需要处理复杂的API函数以及需要数据结构时,类是非常有用的。例如,GetOpenFileName()和GetSaveFileName()函数需要一个包含多个成员的OPENFILENAME结构。你可能不需要利用所有的成员,但它们在那里并且应该初始化。
我喜欢将结构(UDT)和API函数声明封装到一个CfileDialog类中。Class_Initialize事件设置了结构成员的默认值,因此当我使用这个类时,我只需要设置我想要更改的成员(通过属性过程)。标志常量被实现为一个枚举。所以,例如,选择要打开的电子表格,我的代码可能是这样的:
Dim strFileName As String Dim dlgXLS As New CFileDialog With dlgXLS .Title = "Choose a Spreadsheet" .Filter = "Excel (*.xls)|*.xls|All Files (*.*)|*.*" .Flags = ofnFileMustExist OR ofnExplorer If OpenFileDialog() Then strFileName = .FileName End If End With Set dlgXLS = Nothing
该类将默认目录设置为我的文档,但如果我想要的话,可以通过InitDir属性进行更改。
这只是一个类在VBA应用程序中如何极大受益的例子。
当在VBA中使用类的时机是什么?
在VBA中使用类的出现原因可能是为了将多个数据和方法绑定起来,并且在对象创建/终止时进行特定处理。举个例子,如果有几个过程在打开一个表单时触发,并且其中一个过程需要很长时间,你可能决定想要计时每个阶段......
你可以创建一个计时器类,其中包含开始和停止的方法,然后可以添加一个函数来获取到目前为止的时间,并将其记录在一个文本文件中,使用一个表示正在计时的过程名称的参数。你可以编写逻辑只记录最慢的性能供后续调查使用。
然后你可以添加一个进度条对象,其中包含打开、关闭和显示当前动作名称的方法,以及以毫秒为单位的时间和根据之前存储的报告估计剩余时间等功能。
另一个例子可能是,如果你不喜欢Access的用户组功能,你可以创建自己的用户类,其中包含登录和退出的方法,以及组级用户访问控制/审计/记录某些操作/跟踪错误等功能。
当然,你可以使用一组无关的方法和大量的变量传递来实现这些,但对我来说,将所有功能封装在一个类中似乎更好。
你迟早会接近VBA的限制,但它是一种相当强大的语言,如果你的公司将你限制在使用它,你实际上可以得到一些好的、复杂的解决方案。
在VBA中何时使用类?
在VBA中使用类取决于谁将开发和维护代码。对于编写小型临时应用程序的“高级用户”宏编写者来说,使用类可能会感到困惑。但是对于严肃的开发来说,使用类的原因与其他语言中相同。与VB6相同,您具有相同的限制-没有继承-但是可以通过使用接口实现多态。
使用类的一个很好的用途是表示实体及其集合。例如,我经常看到VBA代码将Excel范围复制到二维数组中,然后使用以下代码操作二维数组:
Total = 0 For i = 0 To NumRows-1 Total = Total + (OrderArray(i,1) * OrderArray(i,3)) Next i
将范围复制到具有适当命名属性的对象集合中可以使代码更易读,例如:
Total = 0 For Each objOrder in colOrders Total = Total + objOrder.Quantity * objOrder.Price Next i
另一个例子是使用类来实现RAII设计模式(搜索google)。例如,我可能需要做的一件事是取消保护一个工作表,进行一些操作,然后再次保护它。使用类可以确保即使代码中发生错误,工作表也始终会被重新保护:
--- WorksheetProtector类模块 --- Private m_objWorksheet As Worksheet Private m_sPassword As String Public Sub Unprotect(Worksheet As Worksheet, Password As String) '如果我们没有为工作表定义密码,则不需要执行任何操作 If Len(Password) = 0 Then Exit Sub '如果工作表已经没有受保护,则不需要执行任何操作 If Not Worksheet.ProtectContents Then Exit Sub '取消工作表的保护 Worksheet.Unprotect Password '记住工作表和密码,以便我们可以重新保护 Set m_objWorksheet = Worksheet m_sPassword = Password End Sub Public Sub Protect() '使用与取消保护时相同的密码保护工作表 If m_objWorksheet Is Nothing Then Exit Sub If Len(m_sPassword) = 0 Then Exit Sub '如果工作表已经受保护,则不需要执行任何操作 If m_objWorksheet.ProtectContents Then Exit Sub m_objWorksheet.Protect m_sPassword Set m_objWorksheet = Nothing m_sPassword = "" End Sub Private Sub Class_Terminate() '当此对象超出范围时,重新保护工作表 On Error Resume Next Protect End Sub
然后,您可以使用此代码简化您的代码:
Public Sub DoSomething() Dim objWorksheetProtector as WorksheetProtector Set objWorksheetProtector = New WorksheetProtector objWorksheetProtector.Unprotect myWorksheet, myPassword ... 操作myWorksheet - 可能引发错误 End Sub
当Sub退出时,objWorksheetProtector超出范围,工作表将再次受保护。
这是在VBA中使用类的一个很好的例子。我不确定我是否真的会这样做,但仍然是一个很好的例子。
这是一个很好的例子。我经常不得不在VBA中使用/编写类。我发现,如果您熟悉其他面向对象编程语言的OOP概念和VBA的限制,可以简单地在VBA中表达您的类。最后,我们在Excel中使用的所有这些项都是类结构的对象/属性/方法。与这里那里重复的大量代码相比,它更有意义,易于管理和传输。
太棒了!我使用Debug.Print 1 / 0
创建了一个未处理的错误,但是当我收到关于错误的弹出窗口并单击结束时,Class_Terminate
过程不会触发。因此,只有在通过错误处理或单击“调试”并修改代码以不产生错误的情况下,工作表保护才会恢复。这是预期的吗?
很难说出现了什么预期的情况,没有看到代码。我建议您在所有相关的位置(Class_Initialize,Class_Terminate)创建一个带有Debug.Print的示例。如果有意外发生,请在此处提问。