C#中yield的使用

时间:2021-11-21 09:07:26

yield 关键字向编译器指示它地址的要领是迭代器块。编译器生成一个类来实现迭代器块中暗示的行为。在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器东西供给值。这是一个返回值,例如,在 foreach 语句的每一次循环中返回的值。yield 关键字也可与 break 结合使用,暗示迭代结束。

例子:
yield return <expression>;
yield break;

在 yield return 语句中,将计算 expression 并将功效以值的形式返回给枚举器东西;expression 必需可以隐式转换为 yield 类型的迭代器。

在 yield break 语句中,控制权将无条件地返回给迭代器的挪用方,该挪用方为枚举器东西的 IEnumerator.MoveNext 要领(或其对应的泛型System.Collections.Generic.IEnumerable<T>)或 Dispose 要领。

yield 语句只能呈此刻 iterator 块中,这种块可作为要领、运算符或访谒器的主体实现。这类要领、运算符或访谒器的体受以下约束的控制:

yield 语句不能呈此刻匿名要领中。有关更多信息,请参见匿名要领(C# 编程指南)。

当和 expression 一起使用时,yield return 语句不能呈此刻 catch 块中或含有一个或多个 catch 子句的 try 块中。

对付”yield”这个关键字我已经见过N次了,直到比来我才知道这个关键字所蕴含的力量。我将不才面展示出一些使用”yield”让你的代码有更高可读性和更好性能的例子.

为了让你对yield有一些快速概览,我首先要展示一个没有使用这个关键字的例子,下面的代码很简单,但在我比来的项目中却很常见

IList<string> FindBobs(IEnumerable<string> names) { var bobs = new List<string>(); foreach(var currName in names) { if(currName == "Bob") bobs.Add(currName); } return bobs; }

注意在这里我使用IEnumerable<string>作为参数类型并以IList<string>作为返回类型,凡是来说,我更倾向于在参数输入的类型方面的范畴越宽越好,但在返回类型上面越发严格(译者按:即输入时多用基类或接口,返回时用子类或实现类),对付输入来说,如果你需要用foreach来对其进行循环的话,使用IEnumerable会更有意义。而对付输出(译者按:也就是返回),我使用接口来让实现部分可以转变。在这里我想让挪用者省去生成列表的麻烦,所以我选择list作为返回类型.

而问题在于,我的设计并不具有可链接性,这样的设计需要孕育产生列表作为返回值,实现上,这个列表或许不会很大,但这并不须要

此刻,让我们来看看以“yield”的方法来做这些,而后我会解释如何使用它,以及它事情的道理。

IEnumerable<string> FindBobs(IEnumerable<string> names) { foreach(var currName in names) { if(currName == "Bob") yield return currName; } }

在这个版本中,我们将返回类型改为IEnumerable,并且我们使用”yield return”.注意我再也不需要创建一个列表,此刻是不是有些迷惑的?别着急,在理解它的事情方法的情况它会变的越来越简单.

当使用”yield return”关键词组时,.net会为你生成一大串管道代码,你可以尽管假装这是个魔法。当开始在被挪用的代码中循环时(这里不是list),实现上产生的是这个函数被一遍一遍的挪用,但每一次都从上一次执行退出的部分隔始继续执行.

传统的执行要领

挪用函数

函数执行并返回list

挪用部分使用返回的list

Yield的执行要领

挪用函数

挪用者请求item

下一个item返回

回到法式2

虽然yield执行的实现貌似有些庞大,但我们最终只需要一次“弹出”一个item,而不是创建整个list并返回.

对付句法说,我小我私家认为yield越发简洁,并且对付通报函数的用途表示的更好(译者按:也就是代码可读性),我使用IEnumerable作为返回类型来通知挪用者它可以被foreach循环并且返回数据,而挪用者此刻可以本身决定它是否愿意将返回值存放到列表中,即使这会以性能作为价钱。

在我供给的这个简单例子中,也许你并不能发明很多使用yield的好处,然而,你可以在挪用者需要打消遍历所有的函数供给的内容时节省很多不须要的事情,当你在要领链接时使用yield,你可以省下的事情(时间)或许会成倍叠加。

Ayende已经有了很棒的例子:using yield for a slick pipes & filters implementation,他甚至还讲述了:version that is multi-threaded。这让我感受非常有趣.