我是否需要将工作表作为 ByRef 或 ByVal 传递?
Do I need to pass a worksheet as ByRef or ByVal?
我从一个更大的块中分解了一些代码,需要将工作sheet传递给它...
我没有为该作品分配任何新值sheet,但我正在更改该作品的分页符设置sheet。我是否需要将其作为 ByRef 传递,或者 ByVal 是否足够好?
Private Sub SetPageBreaks(ByRef wsReport As Worksheet)
Dim ZoomNum As Integer
wsReport.Activate
ActiveWindow.View = xlPageBreakPreview
ActiveSheet.ResetAllPageBreaks
ZoomNum = 85
With ActiveSheet
Select Case wsReport.Name
Case "Compare"
Set .VPageBreaks(1).Location = Range("AI1")
ZoomNum = 70
Case "GM"
.VPageBreaks.Add before:=Range("X1")
Case "Drift"
.VPageBreaks.Add before:=Range("T1")
Case Else
.VPageBreaks.Add before:=Range("U1")
End Select
End With
ActiveWindow.View = xlNormalView
ActiveWindow.Zoom = ZoomNum
End Sub
两者都可以,但对于语义正确的代码,更喜欢按值传递 (ByVal
)。
当您按值传递对象变量时,您是在将 指针 的副本 传递给对象。
因此,该过程与 一起工作的是 相同的对象(即更改的 属性 值 将 被调用者),除了它不允许 Set
指向其他东西的指针 - 它 可以 ,但它会在 它自己的副本 这样调用者就不会受到影响。
Public Sub DoSomething()
Dim target As Worksheet
Set target = ActiveSheet
Debug.Print ObjPtr(target)
DoSomethingElse target
Debug.Print ObjPtr(target)
End Sub
Private Sub DoSomethingElse(ByVal target As Worksheet)
Debug.Print ObjPtr(target)
Set target = Worksheets("Sheet12")
Debug.Print ObjPtr(target)
'in DoSomething, target still refers to the ActiveSheet
End Sub
另一方面...
Public Sub DoSomething()
Dim target As Worksheet
Set target = ActiveSheet
Debug.Print ObjPtr(target)
DoSomethingElse target
Debug.Print ObjPtr(target)
End Sub
Private Sub DoSomethingElse(ByRef target As Worksheet)
Debug.Print ObjPtr(target)
Set target = Worksheets("Sheet12")
Debug.Print ObjPtr(target)
'in DoSomething, target now refers to Worksheets("Sheet12")
End Sub
一般情况下,参数应该按值传递。这只是一个不幸的语言怪癖,ByRef
是默认值(VB.NET 已修复)。
non-object个变量也是如此:
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByVal foo As Long)
foo = 12
'in DoSomething, foo is still 42
End Sub
还有...
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByRef foo As Long)
foo = 12
'in DoSomething, foo is now 12
End Sub
如果变量通过引用传递,但从未在过程主体中重新分配,则它可以通过值传递。
如果变量通过引用传递,并在过程主体中重新分配它,那么该过程可能会写成 Function
,实际上 return 改为修改后的值。
如果变量按值传递,并在过程主体中重新分配,那么调用者将看不到更改 - 这会使代码变得可疑;如果过程需要重新分配 ByVal
参数值,如果代码定义了自己的局部变量并分配 that 而不是 ByVal
,代码的意图就会变得更清晰参数:
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByVal foo As Long)
Dim bar As Long
bar = foo
'...
bar = 12
'...
End Sub
这些都是 Rubberduck 中的实际代码检查,作为 VBE add-in 我大量参与,可以分析您的代码并查看这些内容:
Parameter is passed by value, but is assigned a new value/reference. Consider making a local copy instead if the caller isn't supposed to know the new value. If the caller should see the new value, the parameter should be passed ByRef instead, and you have a bug.
http://rubberduckvba.com/Inspections/Details/AssignedByValParameterInspection
A procedure that only has one parameter passed by reference that is assigned a new value/reference before the procedure exits, is using a ByRef parameter as a return value: consider making it a function instead.
http://rubberduckvba.com/Inspections/Details/ProcedureCanBeWrittenAsFunctionInspection
A parameter that is passed by reference and isn't assigned a new value/reference, could be passed by value instead.
http://rubberduckvba.com/Inspections/Details/ParameterCanBeByValInspection
这就是 wsReport
的情况:
我从一个更大的块中分解了一些代码,需要将工作sheet传递给它...
我没有为该作品分配任何新值sheet,但我正在更改该作品的分页符设置sheet。我是否需要将其作为 ByRef 传递,或者 ByVal 是否足够好?
Private Sub SetPageBreaks(ByRef wsReport As Worksheet)
Dim ZoomNum As Integer
wsReport.Activate
ActiveWindow.View = xlPageBreakPreview
ActiveSheet.ResetAllPageBreaks
ZoomNum = 85
With ActiveSheet
Select Case wsReport.Name
Case "Compare"
Set .VPageBreaks(1).Location = Range("AI1")
ZoomNum = 70
Case "GM"
.VPageBreaks.Add before:=Range("X1")
Case "Drift"
.VPageBreaks.Add before:=Range("T1")
Case Else
.VPageBreaks.Add before:=Range("U1")
End Select
End With
ActiveWindow.View = xlNormalView
ActiveWindow.Zoom = ZoomNum
End Sub
两者都可以,但对于语义正确的代码,更喜欢按值传递 (ByVal
)。
当您按值传递对象变量时,您是在将 指针 的副本 传递给对象。
因此,该过程与 一起工作的是 相同的对象(即更改的 属性 值 将 被调用者),除了它不允许 Set
指向其他东西的指针 - 它 可以 ,但它会在 它自己的副本 这样调用者就不会受到影响。
Public Sub DoSomething()
Dim target As Worksheet
Set target = ActiveSheet
Debug.Print ObjPtr(target)
DoSomethingElse target
Debug.Print ObjPtr(target)
End Sub
Private Sub DoSomethingElse(ByVal target As Worksheet)
Debug.Print ObjPtr(target)
Set target = Worksheets("Sheet12")
Debug.Print ObjPtr(target)
'in DoSomething, target still refers to the ActiveSheet
End Sub
另一方面...
Public Sub DoSomething()
Dim target As Worksheet
Set target = ActiveSheet
Debug.Print ObjPtr(target)
DoSomethingElse target
Debug.Print ObjPtr(target)
End Sub
Private Sub DoSomethingElse(ByRef target As Worksheet)
Debug.Print ObjPtr(target)
Set target = Worksheets("Sheet12")
Debug.Print ObjPtr(target)
'in DoSomething, target now refers to Worksheets("Sheet12")
End Sub
一般情况下,参数应该按值传递。这只是一个不幸的语言怪癖,ByRef
是默认值(VB.NET 已修复)。
non-object个变量也是如此:
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByVal foo As Long)
foo = 12
'in DoSomething, foo is still 42
End Sub
还有...
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByRef foo As Long)
foo = 12
'in DoSomething, foo is now 12
End Sub
如果变量通过引用传递,但从未在过程主体中重新分配,则它可以通过值传递。
如果变量通过引用传递,并在过程主体中重新分配它,那么该过程可能会写成 Function
,实际上 return 改为修改后的值。
如果变量按值传递,并在过程主体中重新分配,那么调用者将看不到更改 - 这会使代码变得可疑;如果过程需要重新分配 ByVal
参数值,如果代码定义了自己的局部变量并分配 that 而不是 ByVal
,代码的意图就会变得更清晰参数:
Public Sub DoSomething()
Dim foo As Long
foo = 42
DoSomethingElse foo
End Sub
Private Sub DoSomethingElse(ByVal foo As Long)
Dim bar As Long
bar = foo
'...
bar = 12
'...
End Sub
这些都是 Rubberduck 中的实际代码检查,作为 VBE add-in 我大量参与,可以分析您的代码并查看这些内容:
Parameter is passed by value, but is assigned a new value/reference. Consider making a local copy instead if the caller isn't supposed to know the new value. If the caller should see the new value, the parameter should be passed ByRef instead, and you have a bug.
http://rubberduckvba.com/Inspections/Details/AssignedByValParameterInspection
A procedure that only has one parameter passed by reference that is assigned a new value/reference before the procedure exits, is using a ByRef parameter as a return value: consider making it a function instead.
http://rubberduckvba.com/Inspections/Details/ProcedureCanBeWrittenAsFunctionInspection
A parameter that is passed by reference and isn't assigned a new value/reference, could be passed by value instead.
http://rubberduckvba.com/Inspections/Details/ParameterCanBeByValInspection
这就是 wsReport
的情况: