[C#2] 2-匿名方法
1.匿名方法应用和机制
先看一段代码(C#1.0):
1 //这里加了参数<为了说明delegate关键字后面的参数列表>
2 public delegate void MyDelegate(object sender, EventArgs e);
3 class Program
4 {
5 static void Main()
6 {
7 new Program().function();
8 }
9 private void function()
10 {
11 MyDelegate md1 = new MyDelegate(MyMethod);
12 md1(this, EventArgs.Empty);
13 }
14 private void MyMethod(object sender, EventArgs e)
15 {
16 Console.WriteLine("C#1.0写法");
17 }
18 }
到了C#2.0时就可以省略掉起到为多委托声明的书写,直接内联方式写MyMethod方法:
private void function()
{
MyDelegate md2 = delegate { Console.WriteLine("C#2.0写法"); };
md2(this,EventArgs.Empty);
}
难道真的省去了中间的方法了吗?看看IL代码:
发现多了一个《'<function>b__0'》的静态方法,如下是此方法代码:
//编译器还是产生了一个方法,这个方法名很怪<以使用匿名方法的所在方法名开头>
//注意delegate { Console.WriteLine("C#2.0写法"); };的delegate 后面我们没有写
//参数<所以匿名方法内部将用不到参数了>,编译器产生了些命名奇怪的参数
.method private hidebysig static void '<function>b__0'(object A_0,
class [mscorlib]System.EventArgs A_1) cil managed
{
//下面这两行表示这些代码是编译器产生的,而不是我们手动写的
.custom instance void[mscorlib]System.Runtime.CompilerServices
.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr bytearray (43 00 23 00 32 00 2E 00 30 00 99 51 D5 6C ) // C.#.2...0..Q.l
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Program::'<function>b__0'
在delegate关键字后面可以不指定参数[结果就是你无法使用参数,但是参数还是实实在在的存在的,只是它的命名是编译器决定的,很奇怪的名字,你拿不到], 但是如果指定参数,则必须全部指定,拿上面的例子说,我只用到了[object sender和EventArgs e中的一个参数],只指定一个行不行,答案是不行的,你要么不指定,要么全部指定, 从委托的签名来说这点很好理解
匿名方法允许我们以内联的方式简化代码书写[本质还是相同的,并没有性能的提升,只是把我们以前做的工作由编译器代做了]。 注意到编译器生成的这个方法是个静态方法,看过有些文章说用在实例方法内部的匿名方法会产生一个实例方法,说的不完整, 我做过几个测试,结果是在前提条件是在实例方法中,当你用到实例成员时,编译器才会产生实例方法,当你没有用到时, 编译器产生一个静态方法。当然在静态方法中使用匿名方法则产生一个"匿名"的静态方法,而不会是实例方法了。
2.匿名方法的中的"外部变量"
这个外部变量指的是匿名方法所在的方法里的局部变量,对与匿名方法来说称作外部变量, 改写下上面的代码[只改了function这个方法,其他没动]:
private void function()
{
int i = 10;
MyDelegate md2 = delegate
{
i++;
Console.WriteLine("C#2.0写法");
};
md2(this, EventArgs.Empty);
}
虽然声明的这个i没做什么实质性的工作,但是它却使编译器做了很多额外的工作,看图:
我们的《'<function>b__0'》跑到一个内部类里去了,编译器调用到外部变量产生了一个内部类[私有密封的类]! 而把外部变量作为了这个类的一个共有字段,我还原下改写的那个function方法[注:把上图用友好点的代码写一下]:
1 private void function()
2 {
3 Temp tempClass = new Temp();
4 tempClass.i = 10;
5 MyDelegate md2 = new MyDelegate(tempClass.TempMethod);
6 md2(this, EventArgs.Empty);
7 }
8 private sealed class Temp
9 {
10 public int i;
11
12 public void TempMethod(object sender, EventArgs e)
13 {
14 i++;
15 Console.WriteLine("C#2.0写法");
16 }
17 }
这个开销还是蛮大的[另外i的值也变的不确定了,慎用外部变量!],用new一个类实现外部变量的传递。 外部变量的生命周期被延长了,一直持续到引用该匿名方法的委托符合垃圾回收的条件为止。对i的引用是在创建该委托时捕获的。 匿名方法不能访问外部范围的ref和out参数。
3.总结
总结:C#2.0中的匿名方法仅仅是编译器简化我们创建委托实例的过程,是一种语法糖,与C#1.0中的写法没有本质的区别。另外匿名方法不是方法...
- 前FDIC主席:比特币政策不应打击加密货币发展
- 任何人都不应该控制区块链供应链
- c# IO操作(带进度的文件复制器,读取文本文件的指定行)
- 高科技来了!玩游戏一样开船的时代来了……
- C++库大全
- 人工智能行业前景预测 全球市场或超2700亿元
- Arxiv网络科学论文摘要14篇
- 工信部:网络强国建设2018年重点工作任务
- 刚刚!张小龙再出重磅!微信小程序掀起新零售红利狂潮!
- 无人驾驶系列——深度学习笔记:Tensorflow的安装-windows系统
- 2018年12大顶级云安全威胁
- 缤果盒子为域名意识打call 六位数秒下bingobox.com
- 用Qt写软件系列二:QCookieViewer(浏览器Cookie查看器)
- 用Qt写软件系列一:QCacheViewer(浏览器缓存查看器)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法