【发布时间】:2023-03-24 10:59:01
【问题描述】:
我正在使用 .NET Framework 4.0。
神奇之处在于OrderBy() LINQ 方法。这里有几个例子供你参考:
var list = new List<int> { 1, 2, 3, 4, 5, 6};
foreach (var item in list)
{
if (item % 2 == 0)
list.Remove(item);
}
正如预期的那样,这个循环抛出了"System.InvalidOperationException: Collection was modified; enumeration operation may not execute." 异常。
但是,如果我添加对OrderBy() 的调用:
foreach (var item in list.OrderBy(v => v))
{
if (item % 2 == 0)
list.Remove(item);
}
代码执行得很好,从列表中删除了所有偶数。
起初我认为OrderBy() 只是枚举了源列表并创建了它的排序副本。这将是有道理的,并解释了为什么循环不会引发异常:我没有枚举与我正在修改的列表相同的列表。但是在the documentation(“备注”部分)中声明:
这个方法是通过延迟执行来实现的。立即返回值是一个存储执行操作所需的所有信息的对象。在通过直接调用其 GetEnumerator 方法或使用 Visual C# 中的 foreach 或 Visual Basic 中的 For Each 枚举对象之前,不会执行此方法表示的查询。
那么这是文档中的错误(可能是此块的意外复制粘贴?)还是我错过了什么?
附:有this question,但投票最多的answer 假定OrderBy() 只是列举了这个列表。我很想知道它是否属实(对一些.NET源的引用
非常受欢迎)。也许副本确实没有创建,但是在我修改之前完全枚举了源列表?
【问题讨论】:
-
list.OrderBy(v => v)返回OrderedEnumerable<TSource>,它会创建自己的枚举器,这就是为什么list.Remove(...)不会影响list.OrderBy(v => v) -
list.ToList() 或 list.ToArray() 也在工作。
-
@Serge ToList() 很明显,因为它创建了集合的副本,因此将使用另一个枚举器。我从未使用过“ToOrder”,所以我不知道它的行为方式。