2

我有一段代码遍历 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))

但它会导致节点为 Nothing,因为无法转换对象。

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

编辑:如果可以的话,我会尽量避免使用循环进行转换

4

2 回答 2

1

如此处所示,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)
于 2016-12-21T15:08:18.197 回答
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
于 2016-12-21T21:52:08.870 回答