我在LinqPad上尝试了这个简单的查询,并且为了第二个查询的工作原理而头疼,但第一个查询不会改变列表( descen )。
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();
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();
答案 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
永远不会完成。