使用C# yield关键字来提高性能和可读性

对于”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),实现上发生的是这个函数被一遍一遍的调用,但每一次都从上一次执行退出的部分开始继续执行.

传统的执行方法

  1. 调用函数
  2. 函数执行并返回list
  3. 调用部分使用返回的list

Yield的执行方法

  1. 调用函数
  2. 调用者请求item
  3. 下一个item返回
  4. 回到步骤2

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

对于句法说,我个人认为yield更加简洁,并且对于传递函数的用途表现的更好(译者按:也就是代码可读性),我使用IEnumerable作为返回类型来通知调用者它可以被foreach循环并且返回数据,而调用者现在可以自己决定它是否愿意将返回值存放到列表中,即使这会以性能作为代价。

在我提供的这个简单例子中,也许你并不能发现很多使用yield的好处,然而,你可以在调用者需要取消遍历所有的函数提供的内容时节省很多不必要的工作,当你在方法链接时使用yield,你可以省下的工作(时间)或许会成倍叠加。

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

最开始我对yield的保留意见是使用这个关键字或许会导致潜在的性能问题,但实际上,至今为止我还未能发现任何信息来说明关于yield对性能的影响,而我在上面提到提高性能的地方远远大于编译器overhead那部分。

小结

Yield可以让你的代码更加高效并拥有更高的可读性,已经是.net 2.0时代了,我想已经没有什么借口可以阻止我们学习和使用yield.

---------------------------------------------------------------------

译者:这篇文章是我翻译的十个鲜为人知的C#关键字里的pangxiaoliang[北京]流浪者同学在评论中提出的意见,那篇文章只是做了个总结,我发现已经有关于论述更深层次的好文了,所以我就不重复发明轮子直接进行翻译了,在翻译的过程中我也学到了不少.谢谢

原文链接:http://www.ytechie.com/2009/02/using-c-yield-for-readability-and-performance.html

时间: 2024-08-02 11:03:19

使用C# yield关键字来提高性能和可读性的相关文章

C# 中的迭代器 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<

Java编程提高性能时需注意的地方

最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了. 下面是参考网络资源和总结一些在java编程中尽可能做到的一些地方 1.尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面 第一,控制资源的使用,通过线程同步来控制资源的并发访问 第二,控制实例的产生,以达到节约资源的目的 第三,控制

C#中yield关键字理解

yield关键字之前用得较少,但是在做项目开发的过程中也遇到了,当时有点迷惑,就顺便研究学习了一下,以下是个人理解,不到之处欢迎拍砖!废话就到这,上代码: class Program { static void Main(string[] args) { string[] strs = new string[] { "1", "2", "3", "4" }; foreach (var item in GetInts(strs)

CSS性能分析,如何优化CSS提高性能

css匹配原理 在优化css之前我们需要了解下css是怎么进行工作的,我们都知道css是由选择器,属性和属性值构成的. 我们可能会这样写上一行代码 //css .con .loulan1 p span{ display: block; } //html<div class="con">     <div class="loulan">         <p><span>文字</span></p>

初用C/C++扩展Python,提高性能

前段时间写了两篇文章介绍如何提高Python的运行效率,一篇是从python语言本身的角度去介绍的,另一篇是从解释器角度(利用PyPy),有兴趣的可以找着看看.从另外一个角度来介绍如何提高python运行效率,那就是利用c/c++来扩展python提高性能.我们知道python官方网站上下载的python解释器源码是用c语言编写的,所以,也可以利用c/c++来扩展它,以获得较优的执行性能.Python提供了API接口,是我们很方便的能进行扩展,所有这些API都包含在Python.h的头文件里,在

从yield关键字看IEnumerable和Collection的区别

C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易在不经意间掉入它制造的陷阱. 目录 一.一个很简单的例子 二.简单谈谈“延迟赋值” 三.从反射的代码帮助我们更加直接的了解yield导致的延迟赋值 四.如果需要“立即赋值”怎么办? 后记 一.一个很简单的例子 下面是一个很简单的例子:Vector为自定义表示二维向量的类型,Program的静态方法G

Java编程 “提高性能” 应尽力做到

除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了. 下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方. 1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控制资源的并发访问: 第二,控制实例的产生,以达到节约资源的目的: 第三,控制数据共享,在

ruby yield 关键字用法实例

yield关键字我是这样理解,用它来占一个位置,先标记下这个地方将来要写代码的,等到调用的时候,再来编写具体的代码.有点像函数指针,或者C#里的委托,但其实并不太一样. 写测试接口的时候,每次的assert返回值不一样,但函数体大部分是相同的,只有参数不同.正好最近看到了yield,就熟悉一下用法,可以把assert这部分code写在yield 的位置. 例子主要就是test_nodes这个函数的定义 和 它的调用. Code: 1 def generate_nodes(n=3) 2 retur

SQL中使用WITH AS提高性能,使用公用表表达式(CTE)简化嵌套SQL

一.WITH AS的含义     WITH AS短语,也叫做子查询部分(subquery factoring),可以让你做很多事情,定义一个SQL片断,该SQL片断会被整个SQL语句所用到.有的时候,是为了让SQL语句的可读性更高些,也有可能是在UNION ALL的不同部分,作为提供数据的部分. 特别对于UNION ALL比较有用.因为UNION ALL的每个部分可能相同,但是如果每个部分都去执行一遍的话,则成本太高,所以可以使用WITH AS短语,则只要执行一遍即可.如果WITH AS短语所定