C#foreach没有';t在linq.Select()创建的集合上迭代时修改元素的属性

本文关键字:集合 迭代 创建 属性 元素 修改 没有 Select linq C#foreach | 更新日期: 2023-09-27 17:59:02

这个Nunit测试没有通过(我希望它通过)。

class ReferenceObject
{
    public bool Flag { get; set; }
}
[Test]
public void CSharpWhyYouNoWork()
{
    //given
    var someRange = Enumerable.Range(0, 3);
    var selectedEnumerable = someRange.Select(p => new ReferenceObject());
    //when
    foreach (var foreachIterationVariable in selectedEnumerable)
    {
        foreachIterationVariable.Flag = true;
    }
    //then
    Assert.That(selectedEnumerable.All(p => p.Flag));
}

我认为foreach迭代变量是通过引用传递的,所以我希望它修改集合的对象。

有趣的是,如果我使用了一个列表,比如:

someRange.Select(...).ToList();

然后一切都按预期进行,测试通过了——我想知道为什么会发生这种情况。。。

C#foreach没有';t在linq.Select()创建的集合上迭代时修改元素的属性

我想知道为什么会发生这种情况

因为Select返回迭代器,而不是延迟求值的列表或数组。在foreach期间迭代该迭代器一次,然后在Enumerable.All期间另一次。这将导致查询执行两次,每次生成一个IEnumerable<T>

当您使用ToList实现查询时,您会创建一个列表,然后将同一列表迭代两次,从而在Assert中产生所需的效果。

您从来没有创建列表(或任何类型的物化集合),只是一个枚举。foreachEnumerable.Range()一直创建了一个新的枚举,您的最终检查也从Enumerable.Range()一直使用一个新枚举。

您必须创建一个集合或一些持久的东西,以确保修改相同的元素。

枚举可以是一个物化集合,但不一定非得是。

以及对我所看到的术语的澄清;

enumerationan iteration over a number of objects

其给出;

枚举是迭代,但并非所有迭代都是枚举