VBA的设计并未考虑如何在函数内部防止参数被修改。如果想要实现该功能,您需要自行实现保护措施。以下是两种可能实现VBA中const保护的建议。
OP的最终解决方案可以在此
找到。
保护Let和Get方法的参数
以下是一个使用Let和Get属性来防止函数修改类成员变量的示例:
创建一个clsPerson类,并添加以下代码:
Option Explicit
Private m_strName As String
Private m_intAge As Integer
Private m_strAddress As String
Public LockMemberVariables As Boolean
Public Property Get Name() As String
Name = m_strName
End Property
Public Property Let Name(strName As String)
If Not LockMemberVariables Then
m_strName = strName
Else
Err.Raise vbObjectError + 1, , "Member variables are locked!"
End If
End Property
Public Property Get Age() As Integer
Age = m_intAge
End Property
Public Property Let Age(intAge As Integer)
If Not LockMemberVariables Then
m_intAge = intAge
Else
Err.Raise vbObjectError + 1, , "Member variables are locked!"
End If
End Property
Public Property Get Address() As String
Address = m_strAddress
End Property
Public Property Let Address(strAddress As String)
If Not LockMemberVariables Then
m_strAddress = strAddress
Else
Err.Raise vbObjectError + 1, , "Member variables are locked!"
End If
End Property
创建一个普通的代码模块,并包含以下功能:
Option Explicit
Public Sub Main()
Dim Bob As clsPerson
Set Bob = New clsPerson
Bob.Name = "Bob"
Bob.Age = 30
Bob.Address = "1234 Anwhere Street"
Bob.LockMemberVariables = True
PrintPerson Bob
AlterPerson Bob
End Sub
Public Sub PrintPerson(p As clsPerson)
MsgBox "Name: " & p.Name & vbCrLf & _
"Age: " & p.Age & vbCrLf & _
"Address: " & p.Address & vbCrLf
End Sub
Public Sub AlterPerson(p As clsPerson)
p.Name = "Jim"
End Sub
运行
Main()
函数来测试clsPerson类。这是一种基于状态的运行时方法,可以打开和关闭以防止修改类成员。clsPerson中的每个Property Let都会检查LockMemberVariables是否为true,如果是,则在尝试更改其值时抛出错误。如果您将代码修改为
Bob.LockMemberVariables = False
,然后调用AlterPerson,则可以无错误地修改Name。
使用接口保护参数
另一种实现保护的方式是通过接口。事实上,您可能更喜欢这种方式,因为它在编译时起作用。假设您创建了一个名为IProtectedPerson的接口(类),该接口仅支持成员变量的Get操作:
Public Property Get Name() As String
End Property
Public Property Get Age() As Integer
End Property
Public Property Get Address() As String
End Property
然后,您需要重写clsPerson类,使其具有常规的Let和Get方法,并且还实现了IProtectedPerson接口:
Option Explicit
Implements IProtectedPerson
Private m_strName As String
Private m_intAge As Integer
Private m_strAddress As String
Public Property Get Name() As String
Name = m_strName
End Property
Public Property Let Name(strName As String)
m_strName = strName
End Property
Public Property Get Age() As Integer
Age = m_intAge
End Property
Public Property Let Age(intAge As Integer)
m_intAge = intAge
End Property
Public Property Get Address() As String
Address = m_strAddress
End Property
Public Property Let Address(strAddress As String)
m_strAddress = strAddress
End Property
'IProtectedPerson Interface Implementation
Private Property Get IProtectedPerson_Name() As String
IProtectedPerson_Name = Me.Name
End Property
Private Property Get IProtectedPerson_Age() As Integer
IProtectedPerson_Age = Me.Age
End Property
Private Property Get IProtectedPerson_Address() As String
IProtectedPerson_Address = Me.Address
End Property
您需要创建以IProtectedPerson为参数的函数。如果您尝试对私有成员变量进行赋值,代码将无法编译,因为该接口上没有Let函数:
Option Explicit
Public Sub Main()
Dim Bob As clsPerson
Set Bob = New clsPerson
Bob.Name = "Bob"
Bob.Age = 30
Bob.Address = "1234 Anwhere Street"
AlterPerson Bob
AlterProtectedPerson Bob
End Sub
Public Sub AlterPerson(p As clsPerson)
p.Name = "Jim"
End Sub
Public Sub AlterProtectedPerson(p As IProtectedPerson)
p.Name = "Sally"
End Sub
代码无法编译,因为在
AlterProtectedPerson
函数中的 p 没有 Name 的 Property Let。