C#编译器闭包机制
背景
C# 在编译器层面为我们提供了闭包机制(Java7 和 Go 也是这种思路),本文简单的做个解释。
背景知识
你必须了解:引用类型、值类型、引用、对象、值类型的值(简称值)。
关于引用、对象和值在内存的分配有如下几点规则:
- 对象分配在堆中。
- 作为字段的引用分配在堆中(内嵌在对象中)。
- 作为局部变量(参数也是具备变量)的引用分配在栈中。
- 作为字段的值分配在堆中(内嵌在对象中)。
- 作为局部变量(参数也是具备变量)的值用分配在栈中。
- 局部变量只能存活于所在的作用域(方法中的大括号确定了作用域的长短)。
注:按值传递和按引用传递也是需要掌握的知识点,C# 默认是按值传递的。
闭包示例
测试代码

1 private static void Before()
2 {
3 Action[] actions = new Action[10];
4
5 for (var i = 0; i < actions.Length; i++)
6 {
7 actions[i] = () =>
8 {
9 Console.WriteLine(i);
10 };
11 }
12
13 foreach (var item in actions)
14 {
15 item();
16 }
17 }

输出结果

编译器帮我们做了是什么?
编译器帮我们生成的代码(我自己写的,可以使用 Reflector 工具自己查看)

1 private static void After()
2 {
3 Action[] actions = new Action[10];
4
5 var anonymous = new AnonymousClass();
6
7 for (anonymous.i = 0; anonymous.i < actions.Length; anonymous.i++)
8 {
9 actions[anonymous.i ] = anonymous.Action;
10 }
11
12 foreach (var item in actions)
13 {
14 item();
15 }
16 }
17
18 class AnonymousClass
19 {
20 public int i;
21
22 public void Action()
23 {
24 Console.WriteLine(this.i);
25 }
26 }

如何修复上面的问题?
上面的例子不是我们期望的输出,让我们给出两种修改方案:
第一种(借鉴JS)

1 private static void Fix()
2 {
3 Action[] actions = new Action[10];
4
5 for (var i = 0; i < actions.Length; i++)
6 {
7 new Action<int>((j) =>
8 {
9 actions[i] = () =>
10 {
11 Console.WriteLine(j);
12 };
13 })(i);
14 }
15
16 foreach (var item in actions)
17 {
18 item();
19 }
20 }

第二种

1 public static void Fix2()
2 {
3 Action[] actions = new Action[10];
4
5 for (var i = 0; i < actions.Length; i++)
6 {
7 var j = i;
8
9 actions[i] = () =>
10 {
11 Console.WriteLine(j);
12 };
13 }
14
15 foreach (var item in actions)
16 {
17 item();
18 }
19 }

分析
编译器将闭包引用的局部变量转换为匿名类型的字段,导致了局部变量分配在堆中。
备注
C# 编译器帮我们做了非常多的工作,如:自动属性、类型推断、匿名类型、匿名委托、Lamda 表达式、析构方法、await 和 sync、using、对象初始化表达式、lock、默认参数 等等,这些统称为“语法糖”。
C#编译器闭包机制的更多相关文章
- JavaScript——闭包机制
闭包机制是JavaScript的重点和难点,本文希望能帮助大家轻松的学习闭包 一.什么是闭包? 闭包就是可以访问另一个函数作用域中变量的函数.下面列举出常见的闭包实现方式,以例子讲解闭包概念 func ...
- 以python为例讲解闭包机制
以python为例讲解闭包机制 缘起 在学习JS的过程中,总是无可避免的接触到闭包机制,尤其是接触到react后,其函数式的编程思想更是将闭包发扬光大,作为函数式编程的重要语法结构,python自然也 ...
- C++编译器模板机制剖析
思考:为什么函数模板可以和函数重载放在一块.C++编译器是如何提供函数模板机制的? 一.编译器编译原理 什么是gcc gcc(GNU C Compiler)编译器的作者是Richard Stallma ...
- Javascript闭包机制(转)
原文地址:http://www.felixwoo.com/archives/247 参考:http://www.ruanyifeng.com/blog/2009/08/learning_javascr ...
- C#学习笔记----C#中的闭包机制
http://www.cnblogs.com/jiejie_peng/p/3701070.html http://www.cnblogs.com/Ribbon/p/3611457.html “ 若匿名 ...
- JS闭包机制实现为DOM元素循环添加事件
HTML代码: <button type='button' class='btn' id='1'>按钮1</button> <button type='button' c ...
- 探索c#之函数创建和闭包
阅读目录: 动态创建函数 匿名函数不足之处 理解c#中的闭包 闭包的优点 动态创建函数 大多数同学,都或多或少的使用过.回顾下c#中动态创建函数的进化: C# 1.0中: public delegat ...
- C#函数式程序设计之用闭包封装数据
如果一个程序设计语言能够用高阶函数解决问题,则意味着数据作用域问题已十分突出.当函数可以当成参数和返回值在函数之间进行传递时,编译器利用闭包扩展变量的作用域,以保证随时能得到所需要的数据. C#函数式 ...
- c#之函数创建和闭包
c#之函数创建和闭包 阅读目录: 动态创建函数 匿名函数不足之处 理解c#中的闭包 闭包的优点 动态创建函数 大多数同学,都或多或少的使用过.回顾下c#中动态创建函数的进化: C# 1.0中: pub ...
随机推荐
- SSIS从理论到实战,再到应用(6)----SSIS的自带日志功能
原文:SSIS从理论到实战,再到应用(6)----SSIS的自带日志功能 上期回顾: SSIS从理论到实战,再到应用(5)----流程控制之Foreach循环 博主最近新负责了一个ssis大项目的架构 ...
- Unity插件之NGUI学习(8)—— Table和NGUI尺寸转换为世界坐标系尺寸
依据 Unity插件之NGUI学习(2),创建一个UI Root,在UI Root下创建一个Texture作为背景图,并设置图片,在Wiget下调整大小:然后在UI Root下再创建一个Panel. ...
- maven_修改setting ,改为自己私服或者OSC开源中国 [为解决sqlite-jdbc 在中央仓库找不到]
因为项目要使用到sqlite ,虽然有现成的jar,但是考虑的项目的易用统一管理,决定还是用maven 结果纠结了半天 sqlite-jdbc 在maven默认的仓库根本找不着,于是乎修改 setti ...
- java学习笔记1——window7下JDK环境变量配置图解
1. 首先下载Java安装工具包 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.ht ...
- [CLR via C#]7. 常量和字段
原文:[CLR via C#]7. 常量和字段 7.1 常量 常量(constant)是一个特殊的值,它是一个从不变化的值. 在定义常量时,它的值必须在编译时确定.确定之后,编译器将常量的值保存到程序 ...
- Spark集群搭建简配+它到底有多快?【单挑纯C/CPP/HADOOP】
最近耳闻Spark风生水起,这两天利用休息时间研究了一下,果然还是给人不少惊喜.可惜,笔者不善JAVA,只有PYTHON和SCALA接口.花了不少时间从零开始认识PYTHON和SCALA,不少时间答了 ...
- Linux内核源代码情景分析-中断半
一.中断初始化 1.中断向量表IDT初始化 void __init init_IRQ(void) { int i; #ifndef CONFIG_X86_VISWS_APIC init_ISA_irq ...
- 瘸腿蛤蟆笔记29-cocos2d-x-3.2 Box2d物理引擎dynamics模块介绍
转载标明出处:http://blog.csdn.net/notbaron/article/details/38611335 上篇回想 本篇名言:奋斗.寻觅.发现,而不屈服.[诗人丁尼生] 上篇中,我们 ...
- Factorization Machines 学习笔记(二)模型方程
近期学习了一种叫做 Factorization Machines(简称 FM)的算法,它可对随意的实值向量进行预測.其主要长处包含: 1) 可用于高度稀疏数据场景:2) 具有线性的计算复杂度.本文 ...
- 3. SQL Server数据库状态监控 - 可用空间
原文:3. SQL Server数据库状态监控 - 可用空间 数据库用来存放数据,那么肯定需要存储空间,所以对磁盘空间的监视自然就很有必要了. 一. 磁盘可用空间 1. 操作系统命令或脚本.接口或工具 ...