如何使用linq to xml创建多态数组?

时间:2011-12-30 08:01:25

标签: c# .net xml linq

是否可以使用LINQ to XML创建多态类型的数组?

我有3个类,Base,Der1和Der2。 Base是Der1和Der2的基类。我有一个xml文件,其中我有与Der1和Der2 objets对应的节点。我想要做的是解析文件并用Der1和Der2对象填充List。

xml看起来像这样:

<nodes>
    <node type = "Der1" attr1="val1" />
    <node type = "Der2" attr2="val2" />
</nodes>

我试图做但不起作用的是:

List<Base> PMList = 
(from der1node from xmlDoc.Descendants("nodes") 
where der1node.type == ("Der1") 
select new Der1()
{
    Attr1 = der1node.Attribute("attr1").Value
}
).Union<Base>
(from der2node from xmlDoc.Descendants("baseNode") 
where der2node.type == ("Der2") 
select new Der2()
{
    Attr2 = der2node.Attribute("attr2").Value
}
).ToList<Base>();

这里我尝试做的是构造类型为= Der1的Der1对象和类型为Der2的Der2对象,并使用Union将它们一起添加到List中。

然而,这不起作用。如何使用LINQ to XML获取不同类型的对象并将它们放在一个多态集合中?

5 个答案:

答案 0 :(得分:2)

一种方法是在投影之前将新实例强制转换为基类:

List<Base> PMList = (from baseNode from xmlDoc.Descendants("nodes") 
                     where baseNode.type == ("Der1") 
                     select (Base) new Der1() {
                         Attr1 = baseNode.Attribute("attr1").Value
                     }
                    ).Union(
                     from baseNode from xmlDoc.Descendants("baseNode") 
                     where baseNode.type == ("Der2") 
                     select (Base) new Der2() {
                         Attr2 = baseNode.Attribute("attr2").Value
                     }
                    ).ToList();

答案 1 :(得分:2)

将对象表单select选择为Base类型:

(from der1node from xmlDoc.Descendants("nodes") 
where der1node.type == ("Der1") 
select new Der1()
{
    Attr1 = der1node.Attribute("attr1").Value
} as Base
)

答案 2 :(得分:2)

创建序列时,只需确保将投影投射到基本类型,使其成为IEnumerable<Base>而不是IEnumerable<Der1>

List<Base> PMList = 
    (from der1node from xmlDoc.Descendants("nodes") 
     where der1node.type == ("Der1") 
     select new Der1()
     {
         Attr1 = der1node.Attribute("attr1").Value
     } as Base).Union(
    (from der2node from xmlDoc.Descendants("baseNode") 
     where der2node.type == ("Der2") 
     select new Der2()
     {
         Attr2 = der2node.Attribute("attr2").Value
     } as Base)).ToList();

或者,您可以事先调用序列上的Cast<Base>()

List<Base> PMList = 
    (from der1node from xmlDoc.Descendants("nodes") 
     where der1node.type == ("Der1") 
     select new Der1()
     {
         Attr1 = der1node.Attribute("attr1").Value
     }).Cast<Base>().Union(
    (from der2node from xmlDoc.Descendants("baseNode") 
     where der2node.type == ("Der2") 
     select new Der2()
     {
         Attr2 = der2node.Attribute("attr2").Value
     }).Cast<Base>()).ToList();

答案 3 :(得分:1)

另一方面,您是否考虑使用Concat代替联盟?联盟将删除重复项,在您当前的状态不应该是问题 但是,如果在某些时候您覆盖Der1Der2的相等性,某些项可能会突然停止出现在列表中。很高兴意识到这一点。

无论如何,我会这样做:

var items = xmlDoc.Descendants("nodes")
    .Where(d1 => d1.type == ("Der1"))
    .Cast<Base>()
    .Concat(xmlDoc.Descendants("nodes")
        .Where(d2 => d2.type = ("Der2"))
        .Cast<Base>()
    ).ToList();

答案 4 :(得分:0)

我知道这大约是7年后。但是,如果元素的顺序与您的用例相关。在这里,我提供了一种不使用PendingIntent来保留订单的方法。以下代码假定“节点”是根元素

Union