闭包的影响

为了展示闭包的影响,我们看下面这个例子。

var buttons = new Button[10];for(var i = 0; i < buttons.Length; i++)
{var button = new Button();button.Text = (i + 1) + ". Button - Click for Index!";button.OnClick += (s, e) => { Messagebox.Show(i.ToString()); };buttons[i] = button;
}
//如果我们点击按钮会发生什么

这个问题很怪,我在我的JavaScript课程上经常问我的学生。95%的学生会说。显然按钮0显示0,按钮1显示1,等等。而不足5%的学生学习了闭包之后会明白。所有的按钮都会显示10.

局部变量i的值改变了。并且等于buttons.Length。也就是10了。想要避免这个诡异的情况也很简单。如下就行了。

var button = new Button();
var index = i;
button.Text = (i + 1) + ". Button - Click for Index!";
button.OnClick += (s, e) => { Messagebox.Show(index.ToString()); };
buttons[i] = button;

问题解决了,但是index变量是一个值类型,因此保留了“全局”i的一个拷贝

最后一个话题是一个叫做表达式树的东西,他和Lambda表达式协作。并且,他会使得在ASP.NET MVC中的Html扩展方法发生一些很奇妙的东西。关键的问题是:如何发现目标函数

1. 传递进去的变量的名称是什么
2. 方法的主体是什么
3. 函数体里使用了什么类型

Expression 解决了这些问题,他允许我们挖掘生成的表达式树,我们也可以执行传递给Func和Action委托的函数,而且,可以在运行时解析Lambda表达式

我们看一下如何使用Expression 类型的例子

Expression<Func<MyModel, int>> expr = model => model.MyProperty;
var member = expr.Body as MemberExpression;
var propertyName = memberExpression.Member.Name; //当 member != null的时候执行  ...

这是Expression最简单的用法了。规则也相当直接。通过构建一个Expression类型的对象。编译器为生成的解释树生成一些元数据。这个解释树包含所有相关的信息,比如参数和方法体。

方法体包含完整的解释树,我们可以访问这些操作。就像完整的语句一样。也可以操作返回指和类型。当然,返回可以为null,无论如此。大多数情况下。我们对表达式很感兴趣。这和ASP.NET MVC中处理Expression类型的方法是很相似的—可以得到使用的参数的名字,而好处是显而易见的。不会出现名称拼写错误了。也就不会出现因此而出现的编译错误了。

注意:当程序员仅仅对调用的属性的名字感兴趣的时候。有一个更简单,更优雅的解决方案,那就是参数特性CallerMemberName 这个特性可以得到调用方法/属性的名称。而字段被编译器自动填充。因此,如果我们仅仅想知道名字,而不想知道其他更多的信息,那么我我们只需要写出像下面这个例子里的代码就行了。通过调用WhatsMyName() 方法可以返回方法的名字

string WhatsMyName([CallerMemberName] string callingName = null)
{return callingName;
}

Lambda表达式的性能

有一个很大的问题:Lambda表达式有多快?好吧。首先,我们期望他们能和我们一般的函数一样快。下一节里。我们会看到Lambda的MSIL代码和普通的函数没有太大的不同。

最有趣的一个讨论是如果Lambda表达式产生了闭包,将会和使用全局变量的方法一样快。这就产生了一个有趣的问题,和一个区域内局部变量的数目多少会有关系吗?

我们看看测试代码,通过4个不同的指标,我们可以看到普通方法和Lambda方法的不同。

using System;
using System.Collections.Generic;
using System.Diagnostics;namespace LambdaTests
{class StandardBenchmark : Benchmark{const int LENGTH = 100000;static double[] A;static double[] B;static void Init(){var r = new Random();A = new double[LENGTH];B = new double[LENGTH];for (var i = 0; i < LENGTH; i++){A[i] = r.NextDouble();B[i] = r.NextDouble();}}static long LambdaBenchmark(){Func<double> Perform = () =>{var sum = 0.0;for (var i = 0; i < LENGTH; i++)sum += A[i] * B[i];return sum;};var iterations = new double[100];var timing = new Stopwatch();timing.Start();for (var j = 0; j < iterations.Length; j++)iterations[j] = Perform();timing.Stop();Console.WriteLine("Time for Lambda-Benchmark: \t {0}ms", timing.ElapsedMilliseconds);return timing.ElapsedMilliseconds;}static long NormalBenchmark(){var iterations = new double[100];var timing = new Stopwatch();timing.Start();for (var j = 0; j < iterations.Length; j++)iterations[j] = NormalPerform();timing.Stop();Console.WriteLine("Time for Normal-Benchmark: \t {0}ms", timing.ElapsedMilliseconds);return timing.ElapsedMilliseconds;}static double NormalPerform(){var sum = 0.0;for (var i = 0; i < LENGTH; i++)sum += A[i] * B[i];return sum;}}
}

本来用Lambda表达式我们可以把代码写的更好。最终我没有这样做。是为了防止影响看最后的结果。因此,本质上。上述代码里有三个方法
1个是Lambda测试,一个是普通测试,还有一个是在普通测试里调用的方法。而没有的第四个方法其实是我们的lambda表达式。在第一个方法里已经创建了。计算过程很简单,我们随机取数字防止编译器做任何优化。最后我们对普通方法和Lambda方法的不同很有兴趣。

如果我们运行这个测试程序。我们会发现Lambda表达式并不总是比普通方法差。我们惊奇的是有时候甚至Lambda表达式更快一些。然而,在有闭包的情况下,,就不对了。这就是说大多数情况下我们可以毫不犹豫的使用lambda表达式。当使用闭包的时候会出现一点点的性能损失,不过还好,下一节会讲述性能损失的几个原因。
下面是测试输出的结果表

Test Lambda [ms] Normal [ms]
0 45+-1                       46+-1
1 44+-1                       46+-2
2 49+-3                      45+-2
3 48+-2                      45+-2

下图是上表的结果,我们可以看得到普通的方法和Lambda表达式基本上限差不多。当使用Lambda表达式的时候没有太大的性能损失。

第三部分会介绍背后的秘密-MSIL

转载于:https://www.cnblogs.com/lazycoding/archive/2013/01/06/2847579.html

[原译]Lambda高手之路第二部分相关推荐

  1. Hbase高手之路 -- 第二章 -- HBase集群的搭建

    Hbase高手之路 – 第二章 – HBase集群的搭建 一. 下载并安装 1. 下载安装包 2. 上传服务器 3. 解压 tar -zxvf hbase-2.4.10-bin.tar.gz -C . ...

  2. Python编程高手之路——第二章:流程控制

    二.流程控制 2.1 运算方式 计算机的核心部件是CPU,CPU有两个功能,控制和运算: 2.1.1 数学运算 print(a ** b) # 幂 print(a // b) // 取整数 2.1.2 ...

  3. 安卓高手之路 图形系统(2)----------------基于Binder的架构思路)

    在学习安卓的时候最迷惑的就是Binder.图形框架的理解与Binder的理解分不开.前面一篇 [ 安卓高手之路之java层Binder 从代码角度分析了Java层Binder的实现原理.在C++层,这 ...

  4. 安卓高手之路之 ClassLoader

    我不喜欢那些泛泛而谈的去讲那些形而上学的道理,更不喜欢记那些既定的东西.靠记忆去弥补思考的人,容易陷入人云亦云的境地,最后必定被记忆所围困,而最终消亡的是创造力.希望这个高手之路系列能够记录我学习安卓 ...

  5. [js高手之路] html5 canvas系列教程 - 掌握画直线图形的常用API

    我们接着上文[js高手之路] html5 canvas系列教程 - 认识canvas以及基本使用方法继续. 一.直线的绘制 cxt.moveTo( x1, y1 ): 将画笔移动到x1, y1这个点 ...

  6. 《Python高手之路(第3版)》——1.5 Joshua Harlow访谈

    本节书摘来自异步社区<Python高手之路(第3版)>一书中的第1章,第1.5节,作者[法]Julien Danjou,王飞龙 译,更多章节内容可以访问云栖社区"异步社区&quo ...

  7. 【免费直播】零基础Office速通,助您走向Word/Excel/PPT高手之路

     1 关于本门课程 [课程费用] 免费 [讲师介绍]  老宋,MOS讲师,2010年获得WORD和EXCEL 2003版专家级认证,2018年获得OFFICE 2016版大师级认证,OFFICE多年实 ...

  8. JavaScript高手之路:构造函数方式封装对象

    本节的主要内容是讲解new Object方式创建对象以及以这种方式来封装几个有趣的类.我们先来回顾一下new Object是怎么创建对象的,再说一下啊new Object方式创建对象如何演变. new ...

  9. [js高手之路]设计模式系列课程-发布者,订阅者重构购物车

    发布者订阅者模式,是一种很常见的模式,比如: 一.买卖房子 生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色 中介拿到卖主的房 ...

  10. 安卓高手之路 图形系统(4 Measure的算法)

    安卓高手之路 图形系统(4 Measure的算法) - 修补C++ - ITeye技术网站 Java代码   /** * Does the hard part of measureChildren:  ...

最新文章

  1. OC 的反射机制以及使用场景
  2. php 5.4.36 sqlserver,PHP:PHP5.4连接SQLSERVER
  3. 网站外部链接优化如何进一步提升?
  4. try/catch/finally的简单实践
  5. animation of android (1)
  6. ARM嵌入式系统malloc的实现(C源码)
  7. http://www.tldp.org/LDP/abs/abs-guide.txt.gz
  8. 春季:@Component与@Bean
  9. Copula函数理论及实现(三维)-MATLAB
  10. 阿里图标库的基本使用
  11. 改写jtopo滚轮缩放代码
  12. 三菱工控板底层源码_三菱PLC实例代码开源PLC项目源代码参考程序百度云资源下载...
  13. 计算机房电脑装软件,机房轻松批量安装软件
  14. 夏普Android系统,夏普LCD-60\70TX85A及YunOS安卓运行环境安装指南
  15. Js一句话实现打开QQ和客服聊天
  16. Python绘制TSP、VRP问题求解结果图
  17. oracle bpm 表单,Oracle BPM 安全认证
  18. android个人记账软件(附上源码)
  19. 第二章 STC51开发环境搭建
  20. DevExpress GridControl 控件中GridView 加组,加行

热门文章

  1. TFS小记(3):建立团队项目
  2. Mac基础知识:在mac上怎么使用程序坞
  3. NoteBurner iTunes DRM Audio Converter for Mac(苹果DRM音频转换器)
  4. iOS底层探索之KVO(五)—FBKVOController分析
  5. Google 正式发布 Fuchsia OS,Flutter 集成尚存问题
  6. 使用EasyRecovery轻松修复损坏的照片
  7. [Swift][leetcode] 433. 最小基因变化
  8. Seoer,牵起用户与搜索引擎双手的魔术师
  9. TCP/IP 域名系统DNS
  10. Android应用开发基础篇(13)-----GestureDetector(手势识别)