Passing a list's enumerator to a function
-
27-10-2019 - |
Pergunta
It looks like passing a list's enumerator to a function "byval" is quite different than passing it "byref". Essentially, regular "byval" passing will NOT change the caller's "enumerator.Current value", even if the function advances the enumerator. I was wondering if anyone knows why this is the case? Is an enumerator a primitive like an integer, without an object reference, and hence changes to it don't get reflected in the caller?
Here is the sample code:
This function is byval, and gets stuck in an infinite loop, spitting out "1" message boxes, because the enumerator's "current" never advances past 5:
Public Sub listItemsUsingByValFunction()
Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
Dim enumerator = list.GetEnumerator()
enumerator.MoveNext()
While enumerator.Current <= 5
listFirstItemByVal(enumerator)
End While
End Sub
Private Sub listFirstItemByVal(ByVal enumerator As List(Of Integer).Enumerator)
MsgBox(enumerator.Current)
enumerator.MoveNext()
End Sub
This, on the other hand, works just as one would expect:
Public Sub listItemsUsingByRefFunction()
Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
Dim enumerator = list.GetEnumerator()
enumerator.MoveNext()
While enumerator.Current <= 5
listFirstItemByRef(enumerator)
End While
End Sub
Private Sub listFirstItemByRef(ByRef enumerator As List(Of Integer).Enumerator)
MsgBox(enumerator.Current)
enumerator.MoveNext()
End Sub
The difference between the two functions is only whether the listFirstItem__ function accepts a byval or a byref enumerator.
Solução
The reason why you're seeing this behavior is that List(Of T).Enumerator
is a Struct
and not a Class
as is commonly expected. So when you pass the enumerator you pass a copy of it and hence only that copy gets updated when you call MoveNext
Outras dicas
Using the sample code as supplied would not compile using Option Strict On. Fixing that may fix the difference you see.
Public Sub listItemsUsingByValFunction()
Dim list As New List(Of Integer)(New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
Dim enumerator As IEnumerator(Of Integer) = list.GetEnumerator()
enumerator.MoveNext()
Debug.WriteLine("S " & enumerator.Current)
Stop
Do
Debug.WriteLine("W " & enumerator.Current)
If Not listFirstItemByVal(enumerator) Then Exit Do
Loop
End Sub
Private Function listFirstItemByVal(ByVal enumerator As IEnumerator(Of Integer)) As Boolean
Debug.WriteLine("F " & enumerator.Current)
Return enumerator.MoveNext()
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
listItemsUsingByValFunction()
End Sub