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();
然后一切都按预期进行,测试通过了——我想知道为什么会发生这种情况。。。
我想知道为什么会发生这种情况
因为Select
返回迭代器,而不是延迟求值的列表或数组。在foreach
期间迭代该迭代器一次,然后在Enumerable.All
期间另一次。这将导致查询执行两次,每次生成一个IEnumerable<T>
。
当您使用ToList
实现查询时,您会创建一个列表,然后将同一列表迭代两次,从而在Assert
中产生所需的效果。
您从来没有创建列表(或任何类型的物化集合),只是一个枚举。foreach
从Enumerable.Range()
一直创建了一个新的枚举,您的最终检查也从Enumerable.Range()
一直使用一个新枚举。
您必须创建一个集合或一些持久的东西,以确保修改相同的元素。
枚举可以是一个物化集合,但不一定非得是。
以及对我所看到的术语的澄清;
enumeration
是an iteration over a number of objects
其给出;
枚举是迭代,但并非所有迭代都是枚举