Excel 事件处理程序中的 ByVal

ByVal in Excel event-handler

我对 Excel 中某些事件处理程序中 ByVal 关键字的用法有点困惑。

NewSheet 事件示例 (复制自 Excel 2019 Power Programming with VBA, Wiley)

Private Sub Workbook_NewSheet(ByVal Sh As Object)
    If TypeName(Sh) = "Worksheet" Then
        Sh.Cells.ColumnWidth = 35
        Sh.Range("A1") = "Sheet added " & Now()
    End If
End Sub

此代码按预期工作,看起来微不足道。但是想了想,越想越糊涂

根据我的理解,ByVal 意味着 Sh 只是原始工作表对象的副本,使用 ByVal 参数的过程不会导致对原始对象的更改。换句话说,代码所做的应该没有效果。

只有当引用传递给过程时,它们才能修改这些引用引用的对象。

我是不是遗漏了什么?谢谢

P.S。我对传递 reference/value 的大部分理解来自其他编程语言,例如 C#。 VBA 中可能有一些我不知道的特殊之处。

由于您传递的是对象,因此 ByVal 会传递引用的副本(值)。引用的副本(值)仍然指向原始引用所指向的内容。因此,您的方法有效并更改了原始引用所指向的内容。

如果你知道 Java,这在本质上类似于 Java,其中一切都可以说 'pass by value' 但是当你将对象作为参数传递时,你是什么实际上做的是传递引用的副本,而不是引用指向的副本。

在这些情况下,ByVal 会阻止更改原始引用本身的值。

请看下一个:

Module Module1
    Sub Main()
        ' Declare an instance of the class and assign a value to its field.
        Dim c1 As New Class1()
        c1.Field = 5
        Console.WriteLine(c1.Field)
        ' Output: 5

        ' ByVal does not prevent changing the value of a field or property.
        ChangeFieldValue(c1)
        Console.WriteLine(c1.Field)
        ' Output: 500

        ' ByVal does prevent changing the value of c1 itself. 
        ChangeClassReference(c1)
        Console.WriteLine(c1.Field)
        ' Output: 500

        Console.ReadKey()
    End Sub

    Public Sub ChangeFieldValue(ByVal cls As Class1)
        cls.Field = 500
    End Sub

    Public Sub ChangeClassReference(ByVal cls As Class1)
        cls = New Class1()
        cls.Field = 1000
    End Sub

    Public Class Class1
        Public Field As Integer
    End Class
End Module