【问题标题】:Return Iterator Method返回迭代器方法
【发布时间】:2017-03-24 03:25:08
【问题描述】:

FirstMethod 被定义为一个迭代器方法。让SecondMethod 定义为调用FirstMethod,但直接返回结果而不是foreaching 和yielding 它的项目。如果ThirdMethodSecondMethod 的结果进行迭代,是否将整个链视为一次迭代,或者要实现这一点,我必须在yield 内部SecondMethod 吗?

例如

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 之前保留迭代器的“惰性”评估。

【问题讨论】:

  • 您可以在此处的示例中添加一些 Console.WriteLine() 调用并自己回答。

标签: c# iterator


【解决方案1】:

是的,它会保持懒惰。您正在返回一个 IEnumerable&lt;T&gt;,它在被枚举之前不会实现结果。

您的代码的行为方式与省略SecondMethod 并从ThirdMethod 调用FirstMethod 完全相同。

您可以通过在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() 之前什么都不会打印。下面是输出的样子:

退回一个 一 返回两个 二 返回三个 三

【讨论】:

    【解决方案2】:

    为了了解它的工作原理,您可以简单地放置断点并对其进行调试。
    另一种方法是添加一些调试输出点:

    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.
    

    如果我们从Main 中删除foreach,那么我们会得到空输出。

    所以,是的,“惰性”评估被保留,即 SecondMethod 只返回一个 IEnumerable 并且在调用 Main 之后枚举值。

    这正是 LINQ 在链接 LINQ 方法时保留此行为的方式,并且仅在您调用 .ToArray().ToList() 等或使用 foreach 时进行枚举。

    【讨论】:

      猜你喜欢
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多