将FirstMethod
定义为迭代器方法。我们要定义SecondMethod
来调用FirstMethod
,但直接返回结果,而不是foreach
覆盖它并yield
其项目。如果ThirdMethod
迭代SecondMethod
的结果,整个链是否被视为迭代,或者要在yield
内实现此类SecondMethod
?
e.g。
IEnumerable<string> FirstMethod()
{
yield return "one";
yield return "two";
yield return "three";
}
IEnumerable<string> SecondMethod()
{
return FirstMethod();
}
IEnumerable<string> ThirdMethod()
{
foreach (string item in SecondMethod())
{
yield return item;
}
}
void Main()
{
foreach (string item in ThirdMethod())
{
Console.WriteLine(item);
}
}
我意识到我仍然会在此示例中显示所有项目。但是,我关心的是保留迭代器的“懒惰”评估,直到Main
。
答案 0 :(得分:2)
是的,它会保持懒惰。您将返回IEnumerable<T>
,在枚举之前不会实现结果。
您的代码的行为方式与省略SecondMethod
并从FirstMethod
致电ThirdMethod
完全相同。
您可以通过在FirstMethod
IEnumerable<string> FirstMethod()
{
Console.WriteLine("Returning one");
yield return "one";
Console.WriteLine("Returning two");
yield return "two";
Console.WriteLine("Returning three");
yield return "three";
}
现在,使用调试器,在SecondMethod
内放置一个断点。请注意,在开始迭代SecondMethod()
之前,不会打印任何内容。这是输出的样子:
Returning one one Returning two two Returning three three
答案 1 :(得分:1)
为了理解它是如何工作的,你可以简单地放置断点并进行调试 另一种方法是添加一些调试输出点:
IEnumerable<string> FirstMethod()
{
Console.WriteLine("FirstMethod start.");
Console.WriteLine("FirstMethod: one");
yield return "one";
Console.WriteLine("FirstMethod: two");
yield return "two";
Console.WriteLine("FirstMethod: three");
yield return "three";
Console.WriteLine("FirstMethod end.");
}
IEnumerable<string> SecondMethod()
{
Console.WriteLine("SecondMethod start.");
return FirstMethod();
}
IEnumerable<string> ThirdMethod()
{
Console.WriteLine("ThirdMethod start.");
foreach (string item in SecondMethod())
{
Console.WriteLine("ThirdMethod: " + item);
yield return item;
}
Console.WriteLine("ThirdMethod end.");
}
void Main()
{
foreach (string item in ThirdMethod())
{
Console.WriteLine("Main: " + item);
}
}
此代码产生以下呼叫顺序:
ThirdMethod start.
SecondMethod start.
FirstMethod start.
FirstMethod: one
ThirdMethod: one
Main: one
FirstMethod: two
ThirdMethod: two
Main: two
FirstMethod: three
ThirdMethod: three
Main: three
FirstMethod end.
ThirdMethod end.
如果我们从foreach
移除Main
,那么我们会得到空输出。
所以,是的,保留了“懒惰”评估,即SecondMethod
只返回IEnumerable
,并且在Main
中调用后会枚举值。
这正是LINQ在链接LINQ方法时保留此行为的方式,并且仅在您调用.ToArray()
,.ToList()
等或使用foreach
时枚举。