为什么以下每次循环IEnumerable而不是在初始选择期间创建实例?
this.bars = this.values.Select(x => new Bar(x));
我希望循环遍历这些值,然后在那里选择一个新的Bar,但是经过测试后,它不会在那一刻创建任何实例,而是在每次循环时创建新的实例。
private IEnumerable<Bar> bars;
bars字段被声明为IEnuermable,所以我不明白它是如何持有任何类型的函数或闭包。
控制台测试应用的完整来源:
namespace LINQ_Test
{
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
public class Bar
{
private int value;
public Bar(int value)
{
this.value = value;
Debug.WriteLine("CTOR: " + value);
}
}
public class Foo
{
private IEnumerable<Bar> bars;
private IEnumerable<int> values = new int[] { 0, 1234, -1 };
public void LoopValues()
{
Debug.WriteLine("Looping through bars 3 times:");
for (int loop = 0; loop < 3; loop++)
{
foreach (Bar bar in this.bars)
{
}
Debug.WriteLine(" (next loop)");
}
Debug.WriteLine("-\n");
}
public void SetupValues()
{
Debug.WriteLine("Settings up bars:");
this.bars = this.values.Select(x => new Bar(x));
Debug.WriteLine("-\n");
}
}
internal class Program
{
private static void Main(string[] args)
{
Foo foo = new Foo();
foo.SetupValues();
foo.LoopValues();
}
}
}
App输出:
Settings up bars:
-
Looping through bars 3 times:
CTOR: 0
CTOR: 1234
CTOR: -1
(next loop)
CTOR: 0
CTOR: 1234
CTOR: -1
(next loop)
CTOR: 0
CTOR: 1234
CTOR: -1
(next loop)
-
答案 0 :(得分:2)
是的,这是预期的行为,并记录在IEnumerable#Select
documentation中。从那个链接:
此方法通过使用延迟执行来实现。立即返回值是一个对象,它存储执行操作所需的所有信息。直到通过直接调用其
GetEnumerator
方法或在Visual C#中使用foreach
或在Visual Basic中使用For Each
来枚举对象时,才会执行此方法表示的查询。
如果您希望立即完成,请立即枚举,可能使用ToList
。