首页 新闻 会员 周边

foreach 遍历集合时,集合不能改变的问题

0
悬赏园豆:20 [已解决问题] 解决于 2014-11-05 13:25
System.Data.DataTable dt = new System.Data.DataTable();
            dt.Columns.Add("ClassName");
            dt.Columns.Add("Name");

            dt.Rows.Add("1班", "Terry");
            dt.Rows.Add("1班", "AI");

            //1.不转成数组
            var rows = dt.AsEnumerable().Where(t => t.Field<string>("Name") == "Terry");
            //2.转成数组
            //var rows = dt.AsEnumerable().Where(t => t.Field<string>("Name") == "Terry").ToList();

            foreach (DataRow row in rows)
            {
                row.Delete();
            }

对于第一个查询,foreach遍历时,会报"集合已修改 枚举操作可能无法执行"异常。而第二个查询就没问题。

这困惑我的是:我知道foreach遍历集合不可修改,为什么第一个查询返回IEnumerable类型,foreach中delete会报错,而遍历List<T>时却不报错,是List<T>中作了支持吗?

虞兮奈若何的主页 虞兮奈若何 | 初学一级 | 园豆:161
提问于:2014-11-05 12:25
< >
分享
最佳答案
1

1、我知道foreach遍历集合不可修改 

这是错误的理解。


对于删除,你GOOGLE一下,都会告诉你不要在for each里面删除。因为删除会改变列表。

收获园豆:20
爱编程的大叔 | 高人七级 |园豆:30839 | 2014-11-05 12:33

谢谢你的回答,我还是没明白,第二个查询ToList()后为什么不报错?这不也是改变了列表吗?

虞兮奈若何 | 园豆:161 (初学一级) | 2014-11-05 12:42

@虞兮奈若何: linq 的延迟执行

我是糖糖 | 园豆:446 (菜鸟二级) | 2014-11-05 12:44

@虞兮奈若何: 

Safely Removing DataRow In ForEach  stackoverflow

 

看看下面的代码及说明,有助于你理解。

Iterate your list in reverse with a for loop:

for (int i = safePendingList.Count - 1; i >= 0; i--)
{
    // some code
    // safePendingList.RemoveAt(i);
}
Example:

var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
    if (list[i] > 5)
        list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));
Alternately, you can use the RemoveAll method with a predicate to test against:

safePendingList.RemoveAll(item => item.Value == someValue);
Here's a simplified example to demonstrate:

var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));
爱编程的大叔 | 园豆:30839 (高人七级) | 2014-11-05 12:52

@爱编程的大叔: 

明白了,对于第二种查询,因为ToList()新建了List列表,后边foreach中delete()是删掉dt.Rows中的这一行(DataRow是引用类型),而List对象中仍然有这一行,List列表并没有改变。所以正确执行。

虞兮奈若何 | 园豆:161 (初学一级) | 2014-11-05 13:24
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册