为什么这个工作但另一个失败(Linq To Xml)

时间:2012-05-25 09:04:09

标签: c# xml linq linq-to-xml

我在LinqPad上尝试了这个简单的查询,并且为了第二个查询的工作原理而头疼,但第一个查询不会改变列表( descen )。

  • 我如何让它发挥作用。我使用此代码来克隆和修改xml属性值

失败

var doc = XElement.Parse("<Root><Descendants>Welcome</Descendants><Descendants>Stack</Descendants><Descendants>Overflow</Descendants></Root>");
var descen = (from des in doc.Descendants("Descendants") select new XElement(des));
foreach (var desc in descen)
{
    desc.Value += DateTime.UtcNow;
}
descen.Dump();
doc.Dump();

作品

var doc = XElement.Parse("<Root><Descendants>Welcome</Descendants><Descendants>Stack</Descendants><Descendants>Overflow</Descendants></Root>");
var descen = (from des in doc.Descendants("Descendants") select new XElement(des));
foreach (var desc in doc.Descendants("Descendants"))
{
    desc.Value += DateTime.UtcNow;
}
descen.Dump();
doc.Dump();

Stall是我的电脑? WTH

var doc = XElement.Parse("<Root><Descendants>Welcome</Descendants><Descendants>Stack</Descendants><Descendants>Overflow</Descendants></Root>");
var descen = (from des in doc.Descendants("Descendants") select des);
foreach (var desc in descen)
{
    desc.Value += DateTime.UtcNow;
}
var instance = from t in descen select new XElement(t);
doc.Elements("Descendants").LastOrDefault().AddAfterSelf(instance);
descen.Dump();

1 个答案:

答案 0 :(得分:4)

在第一个查询中,descen是从现有元素到 new 元素的投影。它被懒惰地评估 - 每次迭代它时,它将创建新的元素。

在第一种情况下,您迭代descen,并随时修改新元素。但是,这些修改后的元素在创建后很快就会被丢弃 - 它们不是原始文档的一部分。

在第二种情况下,您修改原始文档中的元素,因此当您遍历descen时,它将创建已修改的副本元素,并显示那些。

编辑:如果您要更改descen原始文档,则只需在ToList()的初始化部分末尾添加descen即可。例如:

var descen = (from des in doc.Descendants("Descendants")
              select new XElement(des)).ToList();

或者,更可读的是IMO:

var descen = doc.Descendants("Descendants")
                .Select(x => new XElement(x))
                .ToList();

你的最终代码挂起的原因是当AddAfterSelf迭代instance时,它会添加元素......但这些元素是文档的一部分,这意味着它们是descen的一部分{1}}查询,这意味着它们是instance查询的一部分...因此迭代instance永远不会完成。