迭代IEnumerable <T>时一项被删除

时间:2019-10-17 13:08:18

标签: c# asynchronous async-await ienumerable

我有一个采用IEnumerable的方法,将其进一步过滤并遍历过滤后的集合 修改一个属性。

我观察到一个非常奇怪的行为。

虽然该方法在经过几次迭代后循环遍历了经过过滤的IEnumerable<Entity>(我尚未确切计算出多少次), 其中的一项被删除。

private async Task<bool> UpdateSomeValue(IEnumerable<BusinessEntity> entities, BusinessEntity entityToDelete)
{
    //FIlter the IENumerable
        var entitiesToUpdateSequence = entities
                .Where(f => f.Sequence > entityToDelete.Sequence);

        if (entitiesToUpdateSequence.Any())
        {
                var testList = new List<FormBE>(entitiesToUpdateSequence);

                Debug.WriteLine(entitiesToUpdateSequence.Count()); // 5

                //DUring this loop, after a few iterations, one item gets deleted
                foreach (var entity in testList)
                {
                        entity.Sequence -= 1;
                }

                Debug.WriteLine(entitiesToUpdateSequence.Count()); // 4
                return await _someRepo.UpdateEntitySequence(entityToDelete.Id1, entityToDelete.ID2, testList);
        }

        return await Task.FromResult(true);
}

此方法的调用方式如下:

var entities = await entitiesTask.ConfigureAwait(false);
var entityToDelete = entities.Single(f => f.Key.Equals("someValue"));
var updated = await UpdateSomeValue(entities, entityToDelete);

就是这样,没有其他引用到entities集合中。因此,不能从任何其他线程进行修改。

我暂时通过在列表中复制过滤后的IEnumerable找到一个单词,然后使用该列表进行进一步操作 (循环后,列表内容保持不变。)

什么可能导致此问题?

1 个答案:

答案 0 :(得分:3)

查看Enumerable.Where上的文档。具体来说就是备注。

  

此方法通过使用延迟执行来实现。立即返回值是一个对象,该对象存储执行操作所需的所有信息。在通过直接调用其GetEnumerator方法或在Visual C#中使用foreach或在Visual Basic中使用For Each枚举该对象之前,不会执行此方法表示的查询。

这意味着当您调用Where时,您不一定要取回其中仅包含X个项目的对象,例如ListArray。您将获得一个对象,该对象根据提供的谓词知道如何过滤调用的IEnumerable<T>的{​​{1}}。迭代该对象时,例如使用Where循环或对foreach的调用,将根据您提供的谓词评估源Enumerable.Count()中的每个项目,并且仅对满足该谓词的项目进行评估。返回。

由于您提供的谓词检查了IEnumerable<T>属性,并且您正在第一个Sequence循环内修改该属性,因此第二次迭代foreach的项目与您提供的谓词,因此您的数量减少了。如果您要递增entitiesToUpdateSequence而不是递减,那么您第二次迭代Sequence的结果可能会更高。