我的意思是将参数传递给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没有名称的属性允许。

10-05 21:25