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
我对 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