为什么相同的LINQ表达式在两个不同的foreach循环中表现不同? [英] Why the same LINQ expression behaves differently in two different foreach loops?

查看:156
本文介绍了为什么相同的LINQ表达式在两个不同的foreach循环中表现不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下XML.

<Parts>
  <Part name="Part1" disabled="true"></Part>
  <Part name="Part2" disabled="false"></Part>
  <Part name="Part3" ></Part>
  <Part name="Part4" disabled="true"></Part>  
</Parts>

我想删除其disabled属性设置为true的节点.如果禁用"属性未用于任何零件"元素,则表示该属性未禁用.

I want to remove the nodes for which disabled attribute is set to true. If 'disabled' attribute is not used for any 'Part' element, it means it's not disabled.

我写了以下代码:

XmlNode root = xmlDoc.DocumentElement;
List<XmlNode> disabledNodes = new List<XmlNode>();
foreach(XmlNode node in root.ChildNodes)
{
    if(node.Attributes["disabled"] != null && 
        Convert.ToBoolean(node.Attributes["disabled"].Value))
    {
        disabledNodes.Add(node);
    }
}

foreach (XmlNode node in disabledNodes)
{
    root .RemoveChild(node);
}

此代码按预期从XML中删除了2个节点.

This code removes 2 nodes from the XML as expected.

然后,我编写了以下代码以使代码紧凑:

I then wrote following code to make code compact:

foreach (XmlNode node in root.ChildNodes.Cast<XmlNode>()
    .Where(child => child.Attributes["disabled"] != null && 
    Convert.ToBoolean(child.Attributes["disabled"].Value)))
{
    root.RemoveChild(node); // This line works fine without any exception.
}

我发现此循环仅迭代一次,仅从XML中删除一个节点.

修改后的问题:

现在,当我更改foreach循环时,这次我使用ToList()方法将LINQ表达式的结果转换为List<T>(如@Toni Petrina在他的回答中所建议).这次工作正常!

Now when I change the foreach loop, this time I convert the result of LINQ expression to the List<T> using ToList() method (as suggested by @Toni Petrina in his answer). And this time it works fine !

 foreach (XmlNode node in root.ChildNodes.Cast<XmlNode>()
        .Where(child => child.Attributes["disabled"] != null && 
        Convert.ToBoolean(child.Attributes["disabled"].Value)).ToList())
    {
        root.RemoveChild(node); // This line works fine without any exception.
    }

为什么使用ToList()可使LINQ表达式在foreach循环中按预期工作?任何技术原因为何LINQ的结果在两种不同情况下的行为都不同?

Why the use of ToList() made LINQ expression work in foreach loop as expected? Any technical reason why result of LINQ behaves differently in two different situations?

我正在使用.NET 4.0.

I am using .NET 4.0.

推荐答案

写:

foreach (XmlNode node in root.ChildNodes.Cast<XmlNode>()
    .Where(child => child.Attributes["disabled"] != null && 
    Convert.ToBoolean(child.Attributes["disabled"].Value)).ToList())
{
    root.RemoveChild(node);
}

我添加了额外的ToList()以强制立即执行LINQ表达式.

I've added extra ToList() to force immediate execution of the LINQ expression.

创建LINQ查询时,您将获得一个IEnumerable集合,该集合实际上不保存任何结果.即使您写了所有Select和Where以及许多其他子句,完整的查询也不会在您开始对其进行迭代之前执行.只有这样,实际查询才会运行.

When you create a LINQ query, you get an IEnumerable collection which doesn't actually hold any results. Even though you wrote all those Select and Where and many other clause, the complete query isn't executed before you start iterating over it. Only then is the actually query run.

在原始代码中,您创建了一个查询并开始对其进行迭代.您收到了通过所有LINQ子句并删除第一个节点的第一项.但是,由于您要遍历现在已被修改的根集合,因此迭代将停止.

In the original code, you created a query and started iterating over it. You received the first item that passes through all LINQ clauses and remove the first node. But since you were iterating over root collection which is now modified, the iteration stops.

您不能在foreach循环的主体中更改要迭代的集合.

You cannot change the collection you are iterating over in the body of foreach loop.

这篇关于为什么相同的LINQ表达式在两个不同的foreach循环中表现不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆