Range Over Channels in Visual Basic .NET

In a previous example, we saw how For Each provides iteration over basic data structures. We can also use this syntax to iterate over values received from a queue.

Imports System
Imports System.Collections.Concurrent

Module Program
    Sub Main()
        ' We'll iterate over 2 values in the queue.
        Dim queue As New BlockingCollection(Of String)(2)
        queue.Add("one")
        queue.Add("two")
        queue.CompleteAdding()

        ' This For Each iterates over each element as it's
        ' received from queue. Because we called CompleteAdding
        ' on the queue above, the iteration terminates after
        ' receiving the 2 elements.
        For Each elem In queue.GetConsumingEnumerable()
            Console.WriteLine(elem)
        Next
    End Sub
End Module

To run the program:

$ vbc range-over-channels.vb
$ mono range-over-channels.exe
one
two

This example also showed that it’s possible to complete adding to a non-empty collection but still have the remaining values be received.

In Visual Basic .NET, we use BlockingCollection(Of T) as an equivalent to Go’s buffered channels. The CompleteAdding() method serves a similar purpose to Go’s close() for channels. The GetConsumingEnumerable() method allows us to iterate over the items in the collection as they become available, similar to ranging over a channel in Go.

The For Each loop in VB.NET provides similar functionality to Go’s for range loop when used with the GetConsumingEnumerable() method of a BlockingCollection. It will iterate over the elements in the collection, blocking if necessary until an item is available, and will exit when the collection is empty and completed.