博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linq学习总结(4)——Lambda表达式
阅读量:4562 次
发布时间:2019-06-08

本文共 2345 字,大约阅读时间需要 7 分钟。

Lambda表达式的演化

要了解Lambda表达式,我们首先应从委托说起。.NET中的委托实际上就是C语言中的函数指针,函数通过地址进行引用,只不过.NET中它更加好看了而已。

 
delegate
void
FunctionPoint(
string
str);
static
void
printHello(
string
name)
{
Console.WriteLine(
"
Hello {0}
"
, name);
}
static
void
Main(
string
[] args)
{
FunctionPoint fp
=
printHello;
fp(
"
heqichang
"
);
}
/*
Ouput
* Hello heqichang
*/

然后,委托在.NET2.0中又被精简成了匿名委托

 
delegate
void
FunctionPoint(
string
str);
static
void
Main(
string
[] args)
{
FunctionPoint fp
=
delegate
(
string
name)
{
Console.WriteLine(
"
Hello {0}
"
,name);
};
fp(
"
heqichang
"
);
}
/*
Ouput
* Hello heqichang
*/

匿名委托省略了函数名、返回类型以及参数类型,变得更加轻量

 
delegate
void
FunctionPoint(
string
str);
static
void
Main(
string
[] args)
{
FunctionPoint fp
=
s
=>
Console.WriteLine(
"
Hello {0}
"
,s);
fp(
"
heqichang
"
);
}
/*
Ouput
* Hello heqichang
*/

现在我们看到的表达式就是通过委托一步一步简化而来的。我们的Lambda表达式就是一个简洁的委托。左侧(相对于=>)代表函数的参数,右侧就是函数体。

在System命名空间中,微软已经为我们预定义了几个泛型委托Action、Func、Predicate。Action用于在泛型参数上执行一个操作;Func用于在参数上执行一个操作并返回一个值;Predicate<T>用于定义一组条件并确定参数是否符合这些条件。

 

表达式树

Lambda表达式还有个重要的用途就是用来构建表达式树:

 
static
void
Main(
string
[] args)
{
Expression
<
Func
<
int
,
int
,
int
>>
exp
=
(a, b)
=>
a
*
(b
+
2
);
ParameterExpression param1
=
(ParameterExpression)exp.Parameters[
0
];
ParameterExpression param2
=
(ParameterExpression)exp.Parameters[
1
];
BinaryExpression operation
=
(BinaryExpression)exp.Body;
ParameterExpression left
=
(ParameterExpression)operation.Left;
BinaryExpression operation2
=
(BinaryExpression)operation.Right;
ParameterExpression left2
=
(ParameterExpression)operation2.Left;
ConstantExpression right2
=
(ConstantExpression)operation2.Right;
Console.WriteLine(
"
Decomposed expression: ({0},{1}) => {2} {3} ({4} {5} {6})
"
,
param1.Name, param2.Name, left.Name, operation.NodeType, left2.Name,
operation2.NodeType, right2.Value);
Func
<
int
,
int
,
int
>
func
=
exp.Compile();
Console.WriteLine(func(
2
,
2
));
/*
Ouput
* 8
*/
}

我们上面的lambda表达式构建了这么一个表达式树:

r_Capture2.PNG

闭包

如果将一个变量声明在一个函数内部,该变量就只会在该函数的栈内存中。当函数返回,这个本地变量也同时从栈内存中被清除了。当你在Lambda表达式中使用本地变量时,该变量就会在函数的栈空间清理时被移除。为了防止这样的事发生,当一个依赖于本地变量的Lambda表达式需要从函数中返回时,编译器就会创建一个闭包(Closure,也就是一个包装器类)。

 
static
void
Main(
string
[] args)
{
int
x
=
1
;
Func
<
int
,
int
>
add
=
y
=>
x
+
y;
Console.WriteLine(add(
3
));
/*
Output
* 4
*/
}

我们通过ILDasm可以看到,编译器帮我们自动创建了一个类,用于保存本地变量,以扩展它们的生命周期

r_Capture3.PNG

转载于:https://www.cnblogs.com/heqichang/archive/2011/06/28/2092217.html

你可能感兴趣的文章
Redis拾遗(一)
查看>>
js字符串转换为Json对象的三种写法
查看>>
Is it possible to display icons in a PopupMenu?
查看>>
Atitit.常见的4gl 第四代编程语言 与 dsl
查看>>
Atitit js es5 es6新特性 attilax总结
查看>>
JavaWeb学习记录(三)——网页中文编码问题
查看>>
$( document ).ready()&$(window).load()
查看>>
关于Baidu Map(百度地图SDK)的各种骚b问题!
查看>>
喜欢的一些话(不断更新)
查看>>
mysql 自动记录数据插入及最后修改时间
查看>>
c程序设计语言_习题1-9_将输入流复制到输出流,并将多个空格过滤成一个空格...
查看>>
ZT 80-90年代港台300部电视剧 你看过多少?
查看>>
C/C++关于全局变量和局部变量初始化与不初始化的区别
查看>>
题目1007:奥运排序问题
查看>>
爬虫实例——爬取1元夺宝用户头像(借助谷歌浏览器开发者工具)
查看>>
双目立体匹配经典算法之Semi-Global Matching(SGM)概述:匹配代价计算之Census变换(Census Transform,CT)...
查看>>
Docker关键概念阐述
查看>>
MMORPG服务器架构
查看>>
我们一起成长
查看>>
整合shiro出现的问题
查看>>