我的意思是将参数传递给VBA Sub
,以确保它不会被修改。我会在C中以void mysub( const int i );
的身份进行此操作。
在VBA中(如果有的话)推荐的(即最简单,最便携的方式)是什么?
问题是关于下面的项目3。答案是可以接受的,但问题是可以选择的(对此可能没有定论)。
编辑
根据答案和注释,澄清功能VBA与C的等效性:
通过引用。
在VBA中,Sub mysub(i as Integer)
(默认值或Sub mysub(ByRef i as Integer)
)通过引用获取参数而未从调用方(使用Call mysub(j)
的调用者)“征求许可”,在C中没有完全等效的功能。
在C中,最接近的是void mysub(int * i);
。但是在C语言中,必须通过调用mysub(&j);
对其进行补充,即,调用者才能使它起作用。Sub
可以在被调用的i
内部修改“变量”的值(在VBA中为*i
;在C中为Sub
)。如果是这样,它将自动修改调用方中的值。
传递价值。
在VBA中,Sub mysub(ByVal i as Integer)
对应于来自调用方(使用Call mysub(j)
甚至不知道mysub
接受ByVal
还是ByRef
的值)的值,它对应于
在C中,void mysub(int i);
。Sub
可以在被调用的i
内部修改“变量”(在VBA或C中为Sub
)的值。如果是这样,则不会影响调用方中的值。
按值传递,以const
限定。
在C中,void mysub(const int i);
。Sub
不能在被调用的i
内部修改“变量”(在C中为Sub
,在C中)的值。当然,调用者中的值也不会发生任何变化。
最佳答案
VBA并非旨在防止在函数内部修改参数。如果要这样做,则必须自己实施这些保护措施。以下是关于如何在VBA中实现const保护的两个建议。
OP的最终解决方案位于here。
用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中的每个属性Let都会检查LockMemberVariables是否为true,如果尝试更改其值,则将引发错误。如果要修改代码,使Bob.LockMemberVariables = False
然后调用AlterPerson,它将能够正确修改名称。用接口保护参数
实现保护的另一种方法是通过接口。实际上,您可能更喜欢这样做,因为它可以在编译时使用。假设您创建一个名为IProtectedPerson的接口(类),该接口仅支持为成员变量获取:
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没有名称的属性允许。