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
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