给出一个拥有(并初始化一次)IEnumarable<T>
的类:
public class MyClass
{
public MyClass()
{
Values = Sequence(0, 10).Select(i => Convert(i));
}
public IEnumerable<string> Values { get; private set; }
private static string Convert(int i)
{
string iStr = i.ToString();
Console.WriteLine("Convert: " + iStr);
return iStr;
}
private static IEnumerable<int> Sequence(int start, int end)
{
return Enumerable.Range(start, end - start + 1);
}
}
为什么每次需要myClass.Values
的评估值的用法都会重新评估它们?
例如:
static void Main(string[] args)
{
MyClass myClass = new MyClass();
foreach (var v in myClass.Values)
{
Console.WriteLine(v);
}
foreach (var v in myClass.Values)
{
Console.WriteLine("Value: " + v);
}
}
这将打印20次“转换:”和“值:”。
[我知道将值另存为列表(例如,使用ToList()
)将解决此问题,但据我了解,一旦评估了值,便会从内存中使用值(就像我使用Lazy<T>
然后Values.value
),为什么情况不一样?
这是IEnumerable<T>
的正常行为。当在Select
循环中调用每个项目时,实际上会为集合中的每个项目调用您的投影调用foreach
(但显然您只调用了一次)。
因此,当您使用foreach
循环进行循环时,IEnumerable
对象将调用枚举器,并在集合中有可用项时获取下一项,类似于状态机。
[它跟踪在foreach循环中下一个项目被请求时正在枚举的当前项目,因此再次调用了Convert
方法。
[Materialize