首页 > 解决方案 > 使用 yield return 来描述一个迭代器

问题描述

如果有人检查了我对这个主题的想法并纠正了他们的错误,我将不胜感激。我希望这种类型的“请检查我的想法”不会太违反网站的规则,我的问题更多是试图从一个不太了解的人那里回答某个主题是如何工作的话题。希望它对像我这样的初学者来说可能是有价值的/有见地的,并且可能希望看到对正在发生的事情进行高级但非常基本的描述。

这是我理解主题IEnumerableIEnumerator收益回报的方法。

方式IEnumerableIEnumerator交互非常清晰和自然——我们有两个对象,一个包含集合,一个包含光标。

目前,让我们忽略 yield return 和两个接口之间的联系,只考虑以下概念/问题 - 假设我们的代码在每一行都有一个整数的表达式/计算,我们想创建一个函数f它按顺序执行并返回这些整数,即我们第一次调用f()它将返回在第一行计算的整数,第二次调用它将返回第二个整数,等等。这样做的自然方法是创建某种包含上述代码的辅助类/对象,但除此之外,它还将存储我们在代码中的位置。使用goto这是可以做到的。为了实现这一点,我们指定了一个 yield return 关键字来执行此操作 - 编译器认识到,如果我们有某种代码块,其中包含 yield return,它将为其创建一个帮助器/控制器类。请注意,这个帮助程序类如何作用于代码块已经非常类似于 anIEnumerator作用于IEnumerable什么——它在某种意义上存储了我们所在的“位置”。

接下来我们将使用这个概念并对其进行定义,使其与现有的功能IEnumeratorIEnumerable接口一致。我们将瞄准的基本功能是foreach- 当与实现IEnumerable接口的对象一起使用时,它返回在IEnumeratorvia中实现的光标IEnumerable.GetEnumerator,然后使用 和 的方法沿着集合移动MoveNextcurrent返回分别指向的对象。

所以我们可以使用这个概念的第一种方法是只定义GetEnumerator- 我们简单地将我们想要顺序执行的代码块放在GetEnumerator. 为此,编译器认识到,如果GetEnumeratorcontains的主体yield return,它将创建一个辅助对象(并将此对象返回给最后的调用GetEnumerator),并且此辅助类还将实现方法MoveNextCurrent作为“执行下一行,并分别保存到_current(辅助类的某个字段)和“返回_current”。本质上,GetEnumerator将返回上面两段提到的辅助对象,此外编译器将创建所需的MoveNextCurrent这个帮助对象中的方法,以便它们沿着代码块移动,分别返回值。

我们可以使用该概念的另一种方式是直接“定义”集合并遍历它。所以这一次,我们不只是返回一个IEnumerator/ 助手类,而是返回一个IEnumerable. 但就我们的目的而言,我们真的只是对能够将此对象与foreach. 因此,我们可以做到这一点的一种方法是只做与上面几乎相同的事情——我们将辅助对象实现为 an IEnumerableas IEnumerator——所以我们可以IEnumerable在某些foreach语句中将它作为 an 返回,并且我们将 the 实现GetEnumerator为只是 return this。所以效果和上面的很相似。

上面说的有道理吗?我不清楚的一件事是例如是否foreach可以以某种方式IEnumerator直接使用 - 即我们是否可以执行(foreach element in Enumerator())whereEnumerator()是一个IEnumerator仅返回的函数,而不是IEnumerable. 这没有意义,但我不确定编译器是否无法弄清楚这些事情 - 特别是因为如果它yield return在体内看到它能够决定做如此截然不同的事情,然后它会创建一个辅助对象等,就像我提到的那样,所以我不确定除此之外还有多少其他语法糖。

标签: c#ienumerableienumeratoryield-return

解决方案


推荐阅读