2017-01-23 55 views
2

我从一个较大的块中爆发了一些代码,并且需要将工作表传递给它...我是否需要将工作表作为ByRef或ByVal?

我没有为工作表分配任何新值,但是我正在对该分页设置进行更改片。我是否需要将它作为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 
+2

这可能有助于http://www.windowsdevcenter.com/pub/a/oreilly/windows/ ron/objects.html –

回答

6

要么将​​工作,但对于语义正确的代码,更愿意通过值(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参数值,如果它定义了自己的局部变量和分配代码的意图逐渐明朗的是中代替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插件,我积极参与了,可以分析你的代码,看到这些东西:

ByVal parameter is assigned

参数通过值传递,但被分配了新的值/引用。如果调用者不应该知道新值,请考虑制作本地副本。如果调用者应该看到新的值,那么该参数应该传递给ByRef,而你有一个错误。

http://rubberduckvba.com/Inspections/Details/AssignedByValParameterInspection

Procedure can be written as a function

仅具有一个参数由在程序退出之前分配一个新的值/参考引用传递的过程中,使用ByRef参数作为返回值:考虑将其作为一个函数。

http://rubberduckvba.com/Inspections/Details/ProcedureCanBeWrittenAsFunctionInspection

Parameter can be passed by value

,其通过引用传递和没有被分配一个新的值/参考的参数,可以通过值替代地通过。

http://rubberduckvba.com/Inspections/Details/ParameterCanBeByValInspection

这就是wsReport这里的情况:

Parameter 'wsReport' can be passed by value

+0

我使用了Rubberduck,这就是促使我思考问题的原因。虽然工作表变量从来没有被赋予一个新的值(ByVal可以),但是对表单进行更改的事实(更改通常需要ByRef)让我想知道ByVal是传递对象的最佳实践。 – Rdster

+3

@Rdster由于指针的副本指向同一个工作表,因此对工作表进行的更改* do *“传播” - 它*是*相同的对象。但是,如果你传递给它'ByRef',那么程序可以将它设置为'Nothing',当它返回给调用者时,调用者会丢失指针,因为ByRef允许指针被设置为别的东西。 ..希望这是有道理的。另外,耶伊Rubberduck! –

+0

@Rdster FWIW我认为如果问题的标签是[tag:rubberduck],并且具体询问为什么Rubberduck建议按值传递对象(我的意思是说,这里有一个Rubberduck标签!),我的回答会更专注 - 毫不犹豫地询问任何其他检查! –

相关问题