C#之lambda表达式
从C#3.0开始,可以使用lambda表达式把实现代码赋予委托。lambda表达式与委托(http://www.cnblogs.com/afei-24/p/6762442.html)直接相关。当参数是委托类型时,就可以使用lambda表达式实现委托引用。
static void Main()
{
string mid = ", middle part,"; Func<string, string> anonDel = param =>
{
param += mid;
param += " and this was added to the string.";
return param;
};
Console.WriteLine(anonDel("Start of string")); }
lambda运算符“=>” 的左边是参数列表,右边是lambda变量的方法的实现代码。
1.参数
如果lambda表达式只有一个参数,只写出参数名就可以,像上面的代码。
如果委托使用多个参数,就需要把参数名放到括号中:
Func<double, double, double> twoParams = (x, y) => x * y;
Console.WriteLine(twoParams(3, 2));
可以在括号中给变量名添加参数类型:
Func<double, double, double> twoParamsWithTypes = (double x, double y) => x * y;
Console.WriteLine(twoParamsWithTypes(4, 2));
2.多行代码
如果lambda表达式只有一条语句,在方法块内就不需要花括号和return语句,因为编译器会添加一条隐形的return语句。
Func<double, double, double> twoParams = (x, y) => x * y;
Func<double, double, double> twoParams = (x, y) =>
{
retrun x * y;
}
如果在lambda表达式的实现代码中有多条语句,就必须添加花括号和return语句:
Func<string, string> anonDel = param =>
{
param += mid;
param += " and this was added to the string.";
return param;
};
3.闭包
通过lambda表达式可以访问lambda表达式块外部的变量,这称为闭包。闭包是一个很好的功能,但如果使用不当,会很危险。例如:
int someVal = 5;
Func<int,int> f = x => x+someVal;
假定以后修改了变量someVal,于是调用委托f时,会使用someVa的新值:
someVal = 7;
f(3);//结果为10而不是8.
特别是,通过另一个线程调用lambda表达式时,我们可能不知道进行了这个调用,也不知道外部变量的当前值是什么。
所以在使用闭包时,一定要谨慎!!!
在lambda表达式访问lambda表达式块外部的变量时,编译器在定义lambda表达式时,编译器会创建一个匿名类,它用一个构造函数来传递外部变量。该构造函数取决于从外部传递进来的变量个数和类型。
对于lambda表达式Func<int,int> f = x => x+someVal;
public class AnonymousClass
{
private int someVal;
public AnonymousClass(int someVal)
{
this.someVal = someVal;
} public int AnonymousMethod(int x)
{
retrun x+someVal;
}
}
使用lambda表达式并调用该方法的时,会创建匿名类的一个实例,并传递调用该方法时变量的值。
4.使用foreach语句的闭包
先看下面这个例子:
var values = new List<int>() {10,20,30};
var funcs = new List<Func<int>>();
foreach(var val in values)
{
funcs.Add(() => val);
}
foreach(var f in funcs)
{
Console.WriteLine((f()));
}
第一条foreach语句添加了funcs列表中每个元素。添加到列表中的函数使用lambda表达式。该lambda表达式使用了一个变量val,该变量在lambda表达式的外部定义为foreach语句的循环变量。第二条foreach语句迭代funcs列表,以调用列表中引用的每个函数。
在C#5.0之前版本编译这段代码时,会在控制台输出30三次。这是因为,在第一个foreach循环中使用闭包,所创建的函数是在调用时,而不是在迭代时获得val变量的值。在http://www.cnblogs.com/afei-24/p/6738155.html中介绍foreach时讲到编译器会从foreach语句中创建一个while循环。在C#5.0之前版本中,编译器在while循环外部定义循环变量,在每次迭代中重用这个变量。因此,在循环结束时,该变量的值就是最后一次迭代时的值。要想在使用C#5.0之前版本时,输出10,20,30,需要将代码改为使用一个局部变量:
var values = new List<int>() {10,20,30};
var funcs = new List<Func<int>>();
foreach(var val in values)
{
var v = val;
funcs.Add(() => v);
}
foreach(var f in funcs)
{
Console.WriteLine((f()));
}
在C#5.0中,不再需要做这种代码修改。C#5.0会在while循环的代码中创建一个不同的局部循环变量。
C#之lambda表达式的更多相关文章
- 你知道C#中的Lambda表达式的演化过程吗?
那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...
- Linq表达式、Lambda表达式你更喜欢哪个?
什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...
- 背后的故事之 - 快乐的Lambda表达式(一)
快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...
- Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)
作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...
- java8中lambda表达式的应用,以及一些泛型相关
语法部分就不写了,我们直接抛出一个实际问题,看看java8的这些新特性究竟能给我们带来哪些便利 顺带用到一些泛型编程,一切都是为了简化代码 场景: 一个数据类,用于记录职工信息 public clas ...
- 背后的故事之 - 快乐的Lambda表达式(二)
快乐的Lambda表达式 上一篇 背后的故事之 - 快乐的Lambda表达式(一)我们由浅入深的分析了一下Lambda表达式.知道了它和委托以及普通方法的区别,并且通过测试对比他们之间的性能,然后我们 ...
- CRL快速开发框架系列教程二(基于Lambda表达式查询)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- Lambda 表达式递归用法实例
注意: 使用Lambda表达式会增加额外开销,但却有时候又蛮方便的. Windows下查找子孙窗口实例: HWND FindDescendantWindows(HWND hWndParent, LPC ...
- Spark中Lambda表达式的变量作用域
通常,我们希望能够在lambda表达式的闭合方法或类中访问其他的变量,例如: package java8test; public class T1 { public static void main( ...
- 释放Android的函数式能量(I):Kotlin语言的Lambda表达式
原文标题:Unleash functional power on Android (I): Kotlin lambdas 原文链接:http://antonioleiva.com/operator-o ...
随机推荐
- Ioc在重构代码中的应用
最近lz在写抓工商公式系统(http://www.gsxt.gov.cn/index.html)的爬虫,其中的难点就是在怎么过极验验证码,搞的我不要不要的!如下: 简直是各种坑,被搞的死去活来以后还是 ...
- XAMPP安装报错及解决
FROM:http://www.zeeronsolutions.com/installing-xampp-on-windows-7-user-account-control-uac-warning-m ...
- Omi新成员omi-router正式发布
原文链接-https://github.com/AlloyTeam/omi/blob/master/tutorial omi-router omi-router是Omi框架专属的router插件,文件 ...
- stl1
#include<iostream> #include<map> #include<string> using namespace std; map<st ...
- IOS开发创建开发证书及发布App应用(七)——在iTunes创建填写应用基本信息
7.在iTunes创建填写应用基本信息 依旧打开苹果的开发者网站 https://developer.apple.com/ 点击Member,如下图 (注意,下面的图示是登录之后的) 点击iTunes ...
- 第1章1zabbix快速入门
p.MsoNormal,li.MsoNormal,div.MsoNormal { margin: 0cm; margin-bottom: .0001pt; text-align: justify; t ...
- Java并发编程:volatile 关键字
转自:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html 其实Java语言是支持多线程的,为了解决线程并发的问题,在语言内部 ...
- Xamarin+Prism开发之.net standard化
前面[Visual Studio 2017创建.net standard类库编译出错原因]已经解决.net standard类库的编译问题,现在可以正式进入主题了.作为.net 跨平台开发者也得跟上时 ...
- 修改数据库用户名--CMD环境执行有效
--CMD环境执行有效 --修改数据库用户名 select * from user$ where name='aa'; update user$ set name='bb' where name ...
- WebGL 创建和初始化着色器过程
1.编译GLSL ES代码,创建和初始化着色器供WebGL使用.这些过程一般分为7个步骤: 创建着色器对象(gl.createBuffer()); 向着色器对象中填充着色器程序的源代码(gl.shad ...