VB.Net在并行ForEach中使用XmlNodeList

时间:2016-12-21 14:23:35

标签: vb.net foreach casting parallel-processing xmlnodelist

我有一段代码迭代XmlNodeList中的节点,并根据节点名称为每个节点创建一个不同的对象,并将其添加到列表中进行打印。

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

此代码工作正常,但由于ShapeTemplate和TextblockTemplate构造函数必须完成的所有工作,因此它非常慢。由于订单对象被添加到_items并不重要,我认为加快它的一个好方法是使用parallel.ForEach循环。问题是XmlNodeList不能与parallel.ForEach一起使用,因为它是非泛型集合。我一直在研究如何将XmlNodeList转换为List(Of XmlNode)而没有运气。我一直看到的答案是

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

但是当我尝试它时,我收到一个错误,告诉我' Cast'不是XmlNodeList的成员。

我也试过像这样使用TryCast

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

但是它会导致节点无效,因为无法投射对象。

有没有人知道如何在parallel.ForEach循环中使用XmlNodeList?

编辑:如果我可以

,我试图避免使用循环进行转换

2 个答案:

答案 0 :(得分:1)

here所示,XmlNodeList可以通过List(Of XmlNode)传递给构造函数来转换为通用OfType

' I added so your code could compile.
' I assumed an interface shared by ShapeTemplate and TextblockTemplate
Dim nodeList As XmlNodeList
Dim _items As New List(Of ITemplate)

Dim _nodes As New List(Of XmlNode)(nodeList.OfType(Of XmlNode))

现在是并行循环。请注意,如果要添加到非线程安全集合(例如List),则需要同步将对象添加到列表中。所以我将耗时部分(模板构造函数)与快速操作(添加到列表)分开。这可以改善您的表现。

Dim oLock As New Object
Parallel.ForEach(
    _nodes,
    Sub(node)
        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 ' or, do something else?
        End Select
        SyncLock oLock
            _items.Add(item)
        End SyncLock
    End Sub)

答案 1 :(得分:1)

您可以使用Parallel LINQ代替Parallel.ForEach,这似乎更适合这种转换。这看起来就像普通的LINQ查询,但添加了.AsParallel()

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