c# - 在新子集合中枚举时集合被修改异常

标签 c# linq exception collections

我知道在枚举时更改集合会导致collection was modified异常。 但是,如果我从较大的集合中获取子集合,并且在枚举该子集合时从较大的子集合中删除了一些项目,我仍然会收到此错误。在子集合上调用 ToList 解决了这个问题。但为什么会发生?

var localCollection = someData.ToList(); // from DB Context
var localGrouped = localCollection.GroupBy(x => x.Id).Select(g => new { Id = g.Key, List = g.Select(x => x.Value) }); or .ToList(); // Here how I solve exception

var groups = new List<List<Int64>>();

while (localGrouped.Any())
{
    var newSelected = new List<Int64>();

    var firstGroup = localGrouped.First();
    newSelected.Add(firstGroup.Id);

    localGrouped.Remove(firstGroup);

    var similiarGroups = localGrouped.Where(x => x.List.Intersect(firstGroup.List).Any()).ToList();
    if (similiarGroups.Any())
    {
        foreach (var similiarGroup in similiarGroups)
        {
        //Changing something here in parent collection causes exception
            newSelected.Add(similiarGroup.Id);
            localGrouped.Remove(similiarGroup);
        }
    }
    groupsOfParcels.Add(newSelected);
}

最佳答案

Where 不是子集合,而是过滤器。区别在于 LINQ 工作原理的核心。

您可以将 Where 粗略地视为保存对原始 IEnumerable 的引用,以及一些检查条件的代码和一些说明如何进行的状态它已经走了很远。当您对 Where 的输出执行 getNext() 时,这段代码会遍历原始的 IEnumerable,直到找到满足条件,然后返回它(或到达原始 IEnumerable 的末尾,这意味着它也在 Where 的末尾)。

这是惰性求值 - 它在任何时候都只查看需要的字词。因此,原始的 IEnumerable 必须始终存在且未修改。如果您调用 ToList(),评估将立即进行 - 所有元素将被提取并放入一个列表中,然后再继续。

C# 和 Linq 之神 Jon Skeet 写的关于此的最佳读物。他的帖子包括所有主要 Linq 函数的重新实现以及对实现问题的详细讨论,以便您可以准确地了解它们(可能)是如何工作的。

Introduction

Part 2 - Where(!)

关于c# - 在新子集合中枚举时集合被修改异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23393805/

相关文章:

C# 查询窗口集合

c# - LINQ:如何使用 IQueryable() 选择特定列

Python:如何捕获异常并继续?

c# - 从 C# 中的 div 中删除类

c# - 如果我设置断点,我的 JavaScript 只会调用我的 Web 服务。你知道为什么吗?

c# - IEnumerable<XAttribute> 返回 Null,需要返回属性值

java - 仅第一次捕获异常,第二次捕获异常

java - 使用单个 ExceptionMapper 捕获 Jackson 抛出的任何异常

c# - ASP.NET Web 窗体和关注点分离

c# - 通过 Google SMTP 发送邮件失败