Variant Iterators


Before I get into the details, I want to connect the For Each syntax with the concept of iterators introduced in “Using A List Iterator Class,” page 172. You’ll remember that CList had a CListWalker class that could iterate through the items in a list. To prove it worked, I demonstrated a nested loop. (See page 173.) The outer loop created an iterator object and used it to walk through the list, but in the middle of the walk, the outer iterator suspended operation and created an inner iterator object. When the inner iterator finished walking, it returned control to the outer iterator, which remembered its position and kept walking. The outer and inner iterators were separate objects, each with its own state variables.


The For Each syntax works the same way. If you’re like me, you might program for several years without ever using a nested For Each loop on the same ­collection. But they do work, as this example illustrates:

s = s & sCrLf & “Nested iteration loops with For Each: “ & sCrLf
Dim vAnimal2 As Variant
For Each vAnimal In animals
s = s & Space$(4) & vAnimal & sCrLf
If vAnimal = “Lion” Then
For Each vAnimal2 In animals
s = s & Space$(8) & vAnimal2 & sCrLf
Next
End If
Next

The output looks like this:

Shrew
Wolverine
Lion
Shrew
Wolverine
Lion
Tiger
Bear
Tiger
Bear

Here’s how it works. Each time your code hits a For Each block, Visual Basic creates a new iterator object. The iterator object’s class must implement the IEnumVARIANT interface, and Visual Basic knows that such an object will have a Next method (like the More method of CListWalker). So each time through the loop, Visual Basic calls the Next method and uses the result as the current variant entry.


To enumerate variants, we’ll have to implement IEnumVARIANT in an iterator class. Our collection class will have to create iterator objects of type IEnum­VARIANT. The collection object will have to somehow let Visual Basic know about these iterator objects. Unfortunately, we can’t do any of this stuff directly.