2017-01-23 58 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標籤!),我的回答會更專注 - 毫不猶豫地詢問任何其他檢查! –

相關問題