Rds*_*ter 4 excel vba pass-by-reference excel-vba
我从一个更大的块中打破了一些代码并需要将工作表传递给它...
我没有为工作表分配任何新值,但我正在更改该工作表的分页符设置.我需要将其作为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
Run Code Online (Sandbox Code Playgroud)
两者都可以工作,但对于语义正确的代码,更喜欢通过value(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
Run Code Online (Sandbox Code Playgroud)
另一方面...
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
Run Code Online (Sandbox Code Playgroud)
通常,参数应按值传递.这只是一个不幸的语言怪癖ByRef
是默认的(VB.NET修复).
对于非对象变量也是如此:
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
Run Code Online (Sandbox Code Playgroud)
和...
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
Run Code Online (Sandbox Code Playgroud)
如果变量通过引用传递,但从未在过程体中重新分配,则可以按值传递.
如果变量通过引用传递,并在过程的主体中重新分配,那么该过程可能会被写为a Function
,并实际返回修改后的值.
如果变量按值传递,并在过程体中重新分配,则调用者不会看到更改 - 这会使代码可疑; 如果一个过程需要重新分配一个ByVal
参数值,那么如果代码定义了自己的局部变量并且分配了它而不是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
Run Code Online (Sandbox Code Playgroud)
这些都是Rubberduck中的实际代码检查,因为VBE加入我很大程度上参与其中,它可以分析您的代码并查看以下内容:
参数按值传递,但会分配新值/引用.如果调用者不应该知道新值,请考虑制作本地副本.如果调用者应该看到新值,则应该通过ByRef传递参数,并且您有一个错误.
http://rubberduckvba.com/Inspections/Details/AssignedByValParameterInspection
在过程退出之前,只有一个参数通过引用传递的过程(在过程退出之前分配了一个新值/引用)使用ByRef参数作为返回值:考虑使其成为函数.
http://rubberduckvba.com/Inspections/Details/ProcedureCanBeWrittenAsFunctionInspection
通过引用传递但未分配新值/引用的参数可以通过值传递.
http://rubberduckvba.com/Inspections/Details/ParameterCanBeByValInspection
这就是wsReport
这里的情况: