返回Iterator方法

时间:2017-03-24 03:25:09

标签: c# iterator

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

2 个答案:

答案 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时枚举。