转http://www.cnblogs.com/lazycoding/archive/2013/01/06/2847579.html

闭包的影响

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

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表达式的时候没有太大的性能损失。

Lambda高手之路第二部分的更多相关文章

  1. Lambda高手之路第三部分

    转http://www.cnblogs.com/lazycoding/archive/2013/01/06/2847587.html 背后的秘密-MSIL 通过著名的LINQPad,我们可以更深入的查 ...

  2. Lambda高手之路第一部分

    转http://www.cnblogs.com/lazycoding/archive/2013/01/06/2847574.html 介绍 Lambda表达式是使代码更加动态,易于扩展并且更加快速(看 ...

  3. 安卓高手之路之 ClassLoader

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

  4. ClassLoader使用记录《安卓高手之路》

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

  5. 云计算分布式大数据Hadoop实战高手之路第八讲Hadoop图文训练课程:Hadoop文件系统的操作实战

    本讲通过实验的方式讲解Hadoop文件系统的操作. “云计算分布式大数据Hadoop实战高手之路”之完整发布目录 云计算分布式大数据实战技术Hadoop交流群:312494188,每天都会在群中发布云 ...

  6. [js高手之路] es6系列教程 - 对象功能扩展详解

    第一:字面量对象的方法,支持缩写形式 //es6之前,这么写 var User = { name : 'ghostwu', showName : function(){ return this.nam ...

  7. [js高手之路]深入浅出webpack系列2-配置文件webpack.config.js详解

    接着上文,重新在webpack文件夹下面新建一个项目文件夹demo2,然后用npm init --yes初始化项目的package.json配置文件,然后安装webpack( npm install ...

  8. [js高手之路]Vue2.0基于vue-cli+webpack Vuex用法详解

    在这之前,我已经分享过组件与组件的通信机制以及父子组件之间的通信机制,而我们的vuex就是为了解决组件通信问题的 vuex是什么东东呢? 组件通信的本质其实就是在组件之间传递数据或组件的状态(这里将数 ...

  9. [js高手之路] es6系列教程 - promise常见用法详解(resolve,reject,catch,then,all,race)

    关于promise我在之前的文章已经应用过好几次,如[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist,本文就来讲解下pro ...

随机推荐

  1. 清华集训2014 day2 task3 矩阵变换

    题目 算法 稳定婚姻系统(其实就是贪心) 一个方案不合法,当且仅当下面这种情况: 设第\(i\)行选了数字\(x\),如果第\(j\)行有一个\(x\)在第\(i\)行的\(x\)后面,并且第\(j\ ...

  2. grunt getHTML

    var Base = require( "../common/base" ) , HandlerBase = require( "../common/handlerBas ...

  3. Tuxedo入门学习

    中间件介绍: 介于客户机和server之间的夹层,突破了传统的c/s架构,为构建大规模,高性能,分布式c/s应用程序提供了通信,事物,安全,容错等基础服务,屏蔽了底层应用细节,应用程序不必从底层开发, ...

  4. #AOS应用基础平台# 添加了用户自己定义快捷菜单在平铺布局下的用户自己定义排序管理

    #AOS开发平台# 添加了用户自己定义快捷菜单在平铺布局下的用户自己定义排序管理.

  5. 立贴读 《CLR》

    弱弱的说,我要开始读<CLR>这本书了,怕自己不能坚持下来,特立贴监督自己,本来是大牛们涉及的区域,现在好朋友的鼓励下,勇敢的踏入,如有错误,还请各位指正.

  6. USB基础简介

    一.USB2.0 Universal Serial Bus (通用串行总线)  符合USB总线数据通信要求的通信协议 1.意义 1.易用(热插拔.即插即用) 2.易扩充(USBHub可同时操作127个 ...

  7. Table中的JCheckBox TableHeader的全选(全反选)功能

    菜鸟学习ing class CheckDefaultModel extends DefaultTableModel /* * To change this template, choose Tools ...

  8. HTML - HTML Commonly Used Character Entities

    HTML Entities Some characters are reserved in HTML. It is not possible to use the less than (<) o ...

  9. 用SignalR做类似QQ登录的应用

    原文:用SignalR做类似QQ登录的应用 首先通过NuGet下载signalr包 在工程下新建一个类,继承Hub public class DemoHub:Hub { public class Us ...

  10. Spring MVC 的json问题(406 Not Acceptable)

    原因 : 就是程序转换JSON失败. 在pom.xml 加上 <dependency> <groupId>com.fasterxml.jackson.core</grou ...