vb.netforeachcastingparallel-processingxmlnodelist

VB.Net Use XmlNodeList in a parallel ForEach


I have a piece of code that iterates over the nodes in an XmlNodeList and creates a different object for each one depending on the node name and adds it to a list for printing.

For Each node as XmlNode In nodeList
    Select Case node.Name.ToUpper()
        Case "SHAPE"
            _items.Add(New ShapeTemplate(node, Me))
        Case "TEXTBLOCK"
            _items.Add(New TextblockTemplate(node, Me))
    End Select
Next

This code works fine, but because of all the work that has to be done by the ShapeTemplate and TextblockTemplate constructors, it is VERY slow. Since the order objects are added to _items doesn't matter, I thought a good way to speed it up would be to use a parallel.ForEach loop. The problem is XmlNodeList can't be used with parallel.ForEach because it is a non-generic collection. I've been looking into ways to convert XmlNodeList to List(Of XmlNode) with no luck. The answer I keep seeing come up is

Dim nodes as New List(Of xmlNode)(nodeList.Cast(Of xmlNode)())

But when I try it, I get an error telling me that 'Cast' is not a member of XmlNodeList.

I've also tried using TryCast like this

Dim nodes as List(Of XmlNode) = TryCast(CObj(nodeList), List(Of XmlNode))

but it results in nodes being Nothing because the object can't be cast.

Does anyone know how I can use XmlNodeList in a parallel.ForEach loop?

EDIT: I'm trying to avoid using a loop for the conversion if I can


Solution

  • You could use Parallel LINQ instead of Parallel.ForEach, which seems like a more natural fit for this sort of transformation. This looks just like a normal LINQ query, but with .AsParallel() added.

    Imports System.Linq
    
    ' _items will not be in same order as nodes in nodeList.
    ' Add .AsOrdered() after .AsParallel() to maintain order, if needed.
    _items = (
        From node In nodeList.Cast(Of XmlNode)().AsParallel()
        Select item = CreateTemplate(node)
        Where item IsNot Nothing
    ).ToList()
    
    Function CreateTemplate(node As XmlNode) As ITemplate ' interface or base class for your types
        Dim item As ITemplate
        Select Case node.Name.ToUpper()
            Case "SHAPE"
                item = New ShapeTemplate(node, Me)
            Case "TEXTBLOCK"
                item = New TextblockTemplate(node, Me)
            Case Else
                item = Nothing
        End Select
        Return item
    End Function