在VBA中传递队列对象byval - 调用函数对象不应该在被调用的函数中被更改

时间:2016-01-25 23:25:24

标签: vba excel-vba excel

我试图将队列传递给VBA中的某个函数,并让该函数的操作不影响调用函数中的队列对象。

例如,在下面的代码中,队列的大小为5000.然后队列传递给RemoveOneFromQueue,大小减小到4999.我希望Main_Test中的队列不受RemoveOneFromQueue中的操作的影响。我认为在函数参数中使用ByVal会实现这一点,但它似乎没有帮助。如果可能的话,有什么想法吗?

我不想每次都重新生成队列,因为真实版本需要很长时间才能完成。

Sub Main_Test()
    Dim queue As Object
    Dim i As Long
    Set queue = GenerateQueue()
    Debug.Print queue.Count

    i = RemoveOneFromQueue(queue)
    Debug.Print queue.Count
End Sub

Function GenerateQueue() As Object
    Dim i As Long
    Dim queue As Object
    Set queue = CreateObject("System.Collections.Queue")
    For i = 1 To 5000
        queue.Enqueue i
    Next i
    Set GenerateQueue = queue
End Function

Function RemoveOneFromQueue(ByVal queue As Object) As Double
    Dim i As Long
    i = queue.Dequeue()
    RemoveOneFromQueue = i
End Function

2 个答案:

答案 0 :(得分:0)

在VBA中,不传递对象本身。 您总是传递对实际对象的引用,因此在此场景中是否放置ByVal或ByRef无关紧要,因为两个引用都将指向同一个对象。在该引用对象上调用成员将在任何地方影响它。

但是为了修复你的特定场景,你可以实例化第二个队列并将其设置为queue.clone(),因为Queue类实现了System.ICloneable接口,所以你很幸运...试试这个:

Sub Main_Test()
    Dim queue As Object
    Set queue = GenerateQueue()
    Debug.Print queue.Count '5000
    RemoveOneFromQueue queue
    Debug.Print queue.Count '5000
End Sub

Sub GenerateQueue() As Object
    Dim i As Long
    Dim queue As Object
    Set queue = CreateObject("System.Collections.Queue")
    For i = 1 To 5000
        queue.Enqueue i
    Next i
    Set GenerateQueue = queue
End Function

Sub RemoveOneFromQueue(ByVal q As Object)
    Dim q2 As Object
    Set q2 = q.Clone()
    q2.Dequeue
    Debug.Print q2.Count '4999
End Sub

请记住,在RemoveOneFromQueue完成执行后,q2将不再存在。

但是,您是否传递引用本身ByVal或ByRef仍然很重要,如本示例所示:

Sub MainTest()
   Dim queue as Object
   Set queue = GenerateQueue()
   Debug.Print queue.Count '5000
   ChangeByVal queue
   Debug.Print queue.Count '5000
   ChangeByRef queue
   Debug.Print queue.Count '4999
End Sub

Sub ChangeByVal(ByVal q as Object)
    Dim q2 As Object
    Set q2 = q.Clone()
    q2.Dequeue
    Debug.Print q2.Count '4999
    Set q = q2
End Sub


Sub ChangeByRef(ByRef q as Object)
    Dim q2 As Object
    Set q2 = q.Clone()
    q2.Dequeue
    Debug.Print q2.Count '4999
    Set q = q2
End Sub

答案 1 :(得分:0)

不幸的是,这是不可能的;(

VBA将COM Object作为参考处理。

现在你必须在你出队或复制它之后检查什么是更快的重新加入,或者使用一些本机VBA数组或者某些东西而不是Collection Object,因为它可以传递ByVal(它实际上是一个副本对象)

Function RemoveOneFromQueue(ByVal queue As Object) As Double
    Dim i As Long
    i = queue.Dequeue()
    RemoveOneFromQueue = i
    queue.Enqueue i
End Function