集合对象 - ByRef - ByVal

时间:2014-02-17 15:24:51

标签: vba pass-by-reference ms-access-2013

我在Access 2013中使用VBA。

在常规模块中,有2个程序,RunProc()PopulateCollection()

执行RunProc时,会调用PopulateCollection 传递的参数是名为MyCol的集合实例。

PopulateCollection添加3个项目,然后RunProc继续迭代集合。

我的问题是:

我希望MyCol中的参数RunProc不会被PopulateCollection填充。实现这个目标的正确方法是什么?

为什么PopulateCollection会填充参数和参数?

' --------Module1------------------
Option Compare Database
Option Explicit

Dim i As Integer
Dim MyCol As VBA.Collection

Sub RunProc()
    Set MyCol = New VBA.Collection

    PopulateCollection MyCol

    For i = 1 To MyCol.Count
        Debug.Print MyCol.Item(i)
    Next i
End Sub

Function PopulateCollection(ByRef pMyCol As VBA.Collection)
    For i = 1 To 3
       pMyCol.Add "Item" & i
    Next i            
End Function

这是提出问题的另一种方式:

选项比较数据库 选项明确

Sub Proc1()

    Dim myInt As Integer
    myInt = 1

    Proc2 myInt

    Debug.Print myInt

    myInt = 1

    Proc3 myInt

    Debug.Print myInt

End Sub

Sub Proc2(ByVal pmyInt)

    pmyInt = pmyInt + 1
    Debug.Print pmyInt

End Sub

Sub Proc3(ByRef pmyInt)

    pmyInt = pmyInt + 1
    Debug.Print pmyInt

End Sub

'考虑3个程序:Proc1,Proc2,Proc3

'Proc1调用Proc2和Proc3

'Proc2和Proc3之间的唯一区别是 '参数pmyInt的调用方式不同:ByVal vs ByRef

'Proc2不会更改参数myInt 'Proc3确实改变了参数myInt

'我的问题的根源是为什么同样的行为 '没有展示对象(VBA.Collection) '假设我想不要改变原来的Collection “我该怎么办?

1 个答案:

答案 0 :(得分:6)

在VBA中,对象(例如集合)始终通过引用传递。传递对象ByRef时,会传递对象的地址,PopulateCollection可以更改引用。

当您传递ByVal时,会传递参考的副本。引用的副本仍指向原始Collection,但如果更改副本,则不会更改RunProc中的引用。

Sub RunProc()

    Dim MyCol As Collection
    Dim i As Long

    Set MyCol = New Collection

    PopCollByVal MyCol

    'I changed what pMyCol points to but *after*
    'I populated it when it still pointed to MyCol
    'so this returns 3
    Debug.Print "ByVal: " & MyCol.Count

    PopCollByRef MyCol

    'When I changed the reference pMyCol it changed
    'MyCol so both became a new Collection. This
    'return 0
    Debug.Print "ByRef: " & MyCol.Count

End Sub

Function PopCollByVal(ByVal pMyCol As Collection)

    Dim i As Long

    'The pointer pMyCol is a copy of the reference
    'to MyCol, but that copy still points to MyCol
    For i = 1 To 3
        'I'm changing the object that is pointed to
        'by both MyCol and pMyCol
        pMyCol.Add "Item" & i
    Next i

    'I can change what pMyCol points to, but I've
    'already populated MyCol because that's what
    'pMyCol pointed to when I populated it.
    Set pMyCol = New Collection

End Function
Function PopCollByRef(ByRef pMyCol As Collection)

    Dim i As Long

    'The pointer pMyCol is the actual reference
    'to MyCol
    For i = 1 To 3
        pMyCol.Add "Item" & i
    Next i

    'When I change what pMyCol points to, I also
    'change what MyCol points to because I passed
    'the pointer ByRef. Now MyCol is a new collection
    Set pMyCol = New Collection

End Function