我有一个采用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找到一个单词,然后使用该列表进行进一步操作 (循环后,列表内容保持不变。)
什么可能导致此问题?
答案 0 :(得分:3)
查看Enumerable.Where
上的文档。具体来说就是备注。
此方法通过使用延迟执行来实现。立即返回值是一个对象,该对象存储执行操作所需的所有信息。在通过直接调用其GetEnumerator方法或在Visual C#中使用foreach或在Visual Basic中使用For Each枚举该对象之前,不会执行此方法表示的查询。
这意味着当您调用Where
时,您不一定要取回其中仅包含X个项目的对象,例如List
或Array
。您将获得一个对象,该对象根据提供的谓词知道如何过滤调用的IEnumerable<T>
的{{1}}。迭代该对象时,例如使用Where
循环或对foreach
的调用,将根据您提供的谓词评估源Enumerable.Count()
中的每个项目,并且仅对满足该谓词的项目进行评估。返回。
由于您提供的谓词检查了IEnumerable<T>
属性,并且您正在第一个Sequence
循环内修改该属性,因此第二次迭代foreach
的项目与您提供的谓词,因此您的数量减少了。如果您要递增entitiesToUpdateSequence
而不是递减,那么您第二次迭代Sequence
的结果可能会更高。