两者都可以,但对于语义正确的代码,最好按值传递 (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 已修复)。
对于非对象变量也是如此:
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,实际上返回修改后的值。
如果一个变量是按值传递的,并且在过程体中被重新赋值,那么调用者就不会看到这些变化——这会使代码变得可疑;如果一个过程需要重新分配 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 插件,它可以分析您的代码并查看这些内容:
参数是按值传递的,但被分配了一个新的值/引用。如果调用者不应该知道新值,请考虑制作本地副本。如果调用者应该看到新值,则应该改为通过 ByRef 传递参数,并且您有一个错误。
http://rubberduckvba.com/Inspections/Details/AssignedByValParameterInspection
只有一个通过引用传递的参数在过程退出之前被分配了一个新值/引用的过程正在使用 ByRef 参数作为返回值:考虑将其改为函数。
http://rubberduckvba.com/Inspections/Details/ProcedureCanBeWrittenAsFunctionInspection
通过引用传递且未分配新值/引用的参数可以改为按值传递。
http://rubberduckvba.com/Inspections/Details/ParameterCanBeByValInspection
这里是wsReport的情况: