[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression
继上一章,介绍Extension Method之后,我们接着来介绍另一个重要的特性:Lambda Expression。在前面的两篇文章中,我一再在强调这样的一个概念:C# 3.x新引入的这些特性仅仅反映在Programming Language和相应的Compiler层面。通过编译生成的Assembly的IL和原来并没有本质的改变。从这个意义上讲,所有的这些其实是编译器给我们玩得障眼法而已。Lambda Expression也不例外, Lambda Expression就是一个Anonymous Delegate,无论是Named Delegate也好、Anonymous Delegate也好,其本质也就是一个Delegate。
接下来,我将通过一个简单的Demonstration,由浅入深地分析Lambda Expression,看看编译器到底会编译生成怎样的额外的Code,他们的IL又是如何。
一、Named Delegate
在上面,我说了Lambda Expression本质上就是一个Delegate,我们先不直接来介绍Lambda Expression, 我们先来看看我们最为熟悉的Delegate的例子:
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Artech.LambdaExpression
{
class Program
{
static void Main()
{
_namedMethodDelegate = new Function<int, bool>(SomeMethod);
Function<int, bool> function1 = _namedMethodDelegate;
function1(20);
}
private static Function<int, bool> _namedMethodDelegate;
private static bool SomeMethod(int args)
{
return (args > 0);
}
}
delegate TResult Function<TArgs, TResult>(TArgs args);
}
上面的例子很简单,先定一个Generic Delegate :Function。在Program Class中定义一个Static的Function字段_namedMethodDelegate和与之对应的Method:SomeMethod,判断输入的数字是否大于零。在Main中实例化_namedMethodDelegate,并调用它。
我们通过IL Disassembler这个Utility来看看Main方法的IL代码。为了让对IL Instruction不是很了解的读者更加容易地理解整个执行过程,我加了简单注释。对于那些希望进一步了解整个MSIL Instruction列表的读者,可以参考:MSIL Instruction Table。
{
.entrypoint
// Code size 34 (0x22)
.maxstack 3
.locals init ([0] class Artech.LambdaExpression.Function`2<int32,bool> function1)//Initialize function1
IL_0000: nop
IL_0001: ldnull
IL_0002: ldftn bool Artech.LambdaExpression.Program::SomeMethod(int32)//Pushes the method pointer referenced by SomeMethod.
IL_0008: newobj instance void class Artech.LambdaExpression.Function`2<int32,bool>::.ctor(object,
native int)//Initializer a Artech.LambdaExpression.Function delegate instance.
IL_000d: stsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::_namedMethodDelegate//Stores a static field: _namedMethodDelegate
IL_0012: ldsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::_namedMethodDelegate//Pushes the static field(_namedMethodDelegate) of an object Static .
IL_0017: stloc.0 //Pop the first local variable
IL_0018: ldloc.0 //Pushes the first local variable
IL_0019: ldc.i4.s 20 //Pushes specified 8-bit value (20) as 32-bit
IL_001b: callvirt instance !1 class Artech.LambdaExpression.Function`2<int32,bool>::Invoke(!0)//Calls virtual method of delegate instance.
IL_0020: pop
IL_0021: ret
} // end of method Program::Main
对于Delegate,我无须再作深入的介绍,相信大家早已了如指掌。在这里需要着重提出是,上面介绍的内容将是后续部分的基础,通过后面的对Anonymous Method和Lambda expression介绍,你会发现它们生成的代码结构和上面的是非常相似的。
二、 Anonymous Method Delegate
Anonymous Method是C# 2.0引入的一个非常好用的功能。通过Anonymous Method,我们可以Delegate的实现直接以Inline的方式放入Delegate对象使用的位置,而无须再繁琐地创建一个Delegate,并通过定义在某个Class中具有相同申明的Method来事例化这个Delegate Instance,最后才将这个delegate instance传入需要调用的Method。
我们现在通过Anonymous Method来简化上面的代码。
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Artech.LambdaExpression
{
class Program
{
static void Main()
{
Function<int, bool> function2 = delegate(int args)
{
return args > 0;
};
function2(20);
}
}
delegate TResult Function<TArgs, TResult>(TArgs args);
}
我们通过Reflector分析编译生成的Assembly,我们发现它具有下面的结构。进一步分析Program Class,我们发现它多了两个额外的Static成员:<>9__CachedAnonymousMethodDelegate1和<Main>b__0。这是编译器的功劳。
下面分别是<>9__CachedAnonymousMethodDelegate1和<Main>b__0的定义:
private static Function<int, bool> <>9__CachedAnonymousMethodDelegate1;
[CompilerGenerated]
private static bool <Main>b__0(int args)
{
return (args > 0);
}
是不是我我们上面一节定义的_namedMethodDelegate和SomeMethod这个两个静态成员一样?
我们进一步分析Main Method的IL。
{
.entrypoint
// Code size 43 (0x2b)
.maxstack 3
.locals init ([0] class Artech.LambdaExpression.Function`2<int32,bool> function2)
IL_0000: nop
IL_0001: ldsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0006: brtrue.s IL_001b
IL_0008: ldnull
IL_0009: ldftn bool Artech.LambdaExpression.Program::'<Main>b__0'(int32)
IL_000f: newobj instance void class Artech.LambdaExpression.Function`2<int32,bool>::.ctor(object,
native int)
IL_0014: stsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0019: br.s IL_001b
IL_001b: ldsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: ldc.i4.s 20
IL_0024: callvirt instance !1 class Artech.LambdaExpression.Function`2<int32,bool>::Invoke(!0)
IL_0029: pop
IL_002a: ret
} // end of method Program::Main
和我们上面一节的IL对比,是否出奇地相似。所用我们可以说,我们在第一节中Named Delegate和Anonymous Method Delegate是等效的。
接下来我们通过Lambda Expression实现上面的功能。
三、 Lambda Expression
下面是通过Lambda Expression实现上面相同功能的Code:
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Artech.LambdaExpression
{
class Program
{
static void Main()
{
Function<int, bool> function3 = x => x > 0;
function3(20);
}
}
delegate TResult Function<TArgs, TResult>(TArgs args);
}
我们通过Reflector分析编译生成的Assembly,我们发现它和通过Anonymous Method Delegate实现的完全一样:Program Class,我们发现它多了两个额外的Static成员,它们的名称都完全一样:<>9__CachedAnonymousMethodDelegate1和<Main>b__0。
这两个Static Member:<>9__CachedAnonymousMethodDelegate1和<Main>b__0的定义也于我们通过Anonymous Method Delegate实现时一模一样:
private static Function<int, bool> <>9__CachedAnonymousMethodDelegate1;
[CompilerGenerated]
private static bool <Main>b__0(int args)
{
return (args > 0);
}
我们进一步来看看Main Method的IL。
{
.entrypoint
// Code size 43 (0x2b)
.maxstack 3
.locals init ([0] class Artech.LambdaExpression.Function`2<int32,bool> function3)
IL_0000: nop
IL_0001: ldsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0006: brtrue.s IL_001b
IL_0008: ldnull
IL_0009: ldftn bool Artech.LambdaExpression.Program::'<Main>b__0'(int32)
IL_000f: newobj instance void class Artech.LambdaExpression.Function`2<int32,bool>::.ctor(object,
native int)
IL_0014: stsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0019: br.s IL_001b
IL_001b: ldsfld class Artech.LambdaExpression.Function`2<int32,bool> Artech.LambdaExpression.Program::'<>9__CachedAnonymousMethodDelegate1'
IL_0020: stloc.0
IL_0021: ldloc.0
IL_0022: ldc.i4.s 20
IL_0024: callvirt instance !1 class Artech.LambdaExpression.Function`2<int32,bool>::Invoke(!0)
IL_0029: pop
IL_002a: ret
} // end of method Program::Main
和上面通过
Anonymous Method Delegate实现的时候完全是一样的。
四、Conclusion
现在我们可以得出结论了,Lambda Expression本质上是一个Anonymous Method Delegate,这个Delegate的匿名性仅仅针对Programming language而言,编译器会为它生成一个Named delegate和一个它指向的Method。这个两个额外生成的对象作为使用Anonymous Method Delegate对应的Class的Static Method而存在。从本质上讲和一般的Delegate并没有本质的区别。所以上面我们分别通过Named delegate、Anonymous method delegate和Lambda Expression实现的3个方式是等效的。
C# 3.x相关内容:
[原创]深入理解C# 3.x的新特性(1):Anonymous Type
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part I
[原创]深入理解C# 3.x的新特性(2):Extension Method - Part II
[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression
[原创]深入理解C# 3.x的新特性(4):Automatically Implemented Property
[原创]深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer
[原创]深入理解C# 3.x的新特性(3):从Delegate、Anonymous Method到Lambda Expression相关推荐
- 深入理解C# 3.x的新特性(2):Extension Method[下篇]
四.Extension Method的本质 通过上面一节的介绍,我们知道了在C#中如何去定义一个Extension Method:它是定义在一个Static class中的.第一个Parameter标 ...
- 深入理解C# 3.x的新特性(5):Object Initializer 和 Collection Initializer
深入理解C# 3.x的新特性系列自开篇以后,已经有两个月了.在前面的章节中,我们先后深入讨论了C# 3.x新引入的一些列新特性:Anomynous Type.Extension Method.Lamb ...
- 《深入理解C++11:C++ 11新特性解析与应用》——1.3 C++11特性的分类
1.3 C++11特性的分类 从设计目标上说,能够让各个特性协同工作是设计C++11/0x中最为关键的部分.委员会总希望通过特性协作取得整体大于个体的效果,但这也是语言设计过程中最困难的一点.因此相比 ...
- 《深入理解C++11:C++ 11新特性解析与应用》——导读
前 言 为什么要写这本书 相比其他语言的频繁更新,C++语言标准已经有十多年没有真正更新过了.而上一次标准制定,正是面向对象概念开始盛行的时候.较之基于过程的编程语言,基于面向对象.泛型编程等概念的C ...
- 《深入理解C++11:C++ 11新特性解析与应用》——2.4 宏__cplusplus
2.4 宏__cplusplus 类别:部分人 在C与C++混合编写的代码中,我们常常会在头文件里看到如下的声明: #ifdef __cplusplus extern "C" { ...
- 《深入理解C++11:C++ 11新特性解析与应用》——3.2 委派构造函数
3.2 委派构造函数 类别:类作者 与继承构造函数类似的,委派构造函数也是C++11中对C++的构造函数的一项改进,其目的也是为了减少程序员书写构造函数的时间.通过委派其他构造函数,多构造函数的类编写 ...
- C++ 11三个新特性的简单使用 - std::function、lambda 表达式、智能指针
使用Dev C++:先设置Dev C++ 支持 C++ 11:见此文后部: https://blog.csdn.net/bcbobo21cn/article/details/111466179 1 s ...
- c++11新特性的使用---可变模板参数、lambda、type_traits、optional综合使用
通过惰性求值类的实现综合采用了可变模板参数.lambda.type_traits.optional进行实现 该类功能是:当初始化某个对象时,该对象引用了一个大对象,这个对象的创建需要较长的时间,同时有 ...
- java lambda表达式详解_Java8新特性:Lambda表达式详解
在 Java 版本的历次更新迭代中,Java8 是一个特殊的存在,与以往的版本升级不同.我们对 Java8 似乎抱有更大的期待,因为它是 Java5 之后最重要的一次升级,提供了十多个新特性,其中 L ...
最新文章
- ZOJ 2060----Fibonacci Again
- 字符串类中的StringBuffer,StringBuilder
- 【POJ】2065 SETI
- 太硬核!2亿股万科股票,约53亿元,一次性全部捐给清华,干一件大事!
- C++ 定义 string
- java服务器修改缓存数据,java监控服务器数据存入缓存
- 正则表达式30分钟入门教程--deerchao
- Unknown entity (Hibernate的findById方法参数必须加上包名)
- Effective C# 摘录(3) - 使用C#表达设计
- Linux 中的grep命令单引号,不加任何参数以及双引号的作用
- 解决 IDEA 无法找到 java.util.Date 的问题
- Vue指令之v-if
- mapreduce实现——腾讯大数据QQ共同好友推荐系统【你可能认识的人】
- 手机版支付宝html页面,支付宝手机网页支付代码
- python-web开发[16-18]之Django开发
- 计算机缓存设置方法,电脑缓存设置步骤介绍
- 6-1 另类循环队列 (30 分) 如果用一个循环数组表示队列,并且只设队列头指针Front,不设尾指针Rear,而是另设Count记录队列中元素个数。请编写算法实现队列的入队和出队操作。
- 如何创建海外美区Apple ID,并使用支付宝购买Apple Store礼品卡,十分钟学会
- C++用循环写出一个金字塔
- 表格中自动布局注意和使用自动计算行高
热门文章
- Python + Appium 环境搭建
- 使用 .NET 平台,如何玩转 Universal Windows 应用?
- C++中Set的使用
- 与一线Linux嵌入式开发工程师的对话
- DBA_实践指南系列7_Oracle Erp R12监控OAM(案例)
- 转”使用UBOOT烧写根文件系统和内核的方法
- 关于Swift中的forEach(_:)和for-in loop
- Good Bye 2017
- 用浏览器做人脸检测,竟然这么简单?(附代码)
- mysql5.7.1 zip版本安装记录