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>中作了支持吗?
1、我知道foreach遍历集合不可修改
这是错误的理解。
对于删除,你GOOGLE一下,都会告诉你不要在for each里面删除。因为删除会改变列表。
谢谢你的回答,我还是没明白,第二个查询ToList()后为什么不报错?这不也是改变了列表吗?
@虞兮奈若何: linq 的延迟执行
@虞兮奈若何:
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));
@爱编程的大叔:
明白了,对于第二种查询,因为ToList()新建了List列表,后边foreach中delete()是删掉dt.Rows中的这一行(DataRow是引用类型),而List对象中仍然有这一行,List列表并没有改变。所以正确执行。