.Net 闭包理解
.Net 闭包理解#
这个东西初看是比较难懂,但是一旦理解之后就很容易了,做笔记以加深印象。且看这题
example.1
class Program
{
static void Main(string[] args)
{
var actions = new List<Action>();
for (int i = 0; i < 5; i++)
{
actions.Add(() =>
{
Print(i);
});
}
actions.ForEach(x => x());
}
private static void Print(int i)
{
Console.WriteLine(i);
}
}
运行一下,结果都是5,Why?首先我们都知道,程序执行一个函数的时候,会将这个函数中用到的局部
变量压入一个栈中,退出这个函数的时候,会将栈中的数据清空。上面的代码,第一个Print函数用的i
值应该是第一个i(也就是0)所在地址的值,但是自加之后,地址变了,那么第一个Print函数用的i(也就是0)去
哪里了?我理解的话应该就是变成了一个不安全的地址,访问这个值就会出现问题。为了避免这种情况
的发生,.Net是如何处理的呢,那就是在所有Print函数执行的时候,不让这个i被清理,于是提升了i的
作用域(这个现象就叫闭包),我换个写法
example.2
class Program
{
private static int _i;
static void Main(string[] args)
{
var actions = new List<Action>();
for (_i = 0; _i < 5; _i++)
{
actions.Add(() =>
{
Print(_i);
});
}
actions.ForEach(x => x());
}
private static void Print(int i)
{
Console.WriteLine(i);
}
}
_注意:_此时是不存在
闭包现象的,当然也别以为
.Net就是这么做的,并不是。通过IL反汇编工具查看
example.1的代码,发现它把i封装到了一个匿名的类中,可以这么想,要使一个东西在栈上不被清理,
那就把它放到堆上...,于是用了个匿名类把i当成其属性,代码如下:
class Program
{
static void Main(string[] args)
{
var actions = new List<Action>();
var myClass = new MyClass();
for (var i = 0; i < 5; i++)
{
myClass.i = i;
actions.Add(() =>
{
Print(myClass);
});
}
myClass.i++;
actions.ForEach(x => x());
}
private static void Print(MyClass myClass)
{
Console.WriteLine(myClass.i);
}
}
internal class MyClass
{
public int i
{
get; set;
}
}
如果我们要避免这种情况,该如何做?那就相当于上诉代码每一个循环使用一个新的MyClass
class Program
{
static void Main(string[] args)
{
var actions = new List<Action>();
for (var i = 0; i < 5; i++)
{
var myClass = new MyClass();
myClass.i = i;
actions.Add(() =>
{
Print(myClass);
});
}
actions.ForEach(x => x());
}
private static void Print(MyClass myClass)
{
Console.WriteLine(myClass.i);
}
}
internal class MyClass
{
public int i
{
get; set;
}
}
其实申明MyClass这一步也可以省了,就是如下
class Program
{
static void Main(string[] args)
{
var actions = new List<Action>();
for (var i = 0; i < 5; i++)
{
var i1 = i;
actions.Add(() =>
{
Print(i1);
});
}
actions.ForEach(x => x());
}
private static void Print(int i)
{
Console.WriteLine(i);
}
}
其实上面这个写法是Resharper提示闭包之后给出的解决方案。
以上,就是我看了别人的一些理解,再加上自己的一些理解推敲出来的东西,有许多地方是模糊的,表面的,但
闭包这东西,不理解好像也没什么影响,这里起个抛砖引玉的作用,欢迎斧正拍砖。
.Net 闭包理解的更多相关文章
- javascript闭包理解
//闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...
- JavaScript中的闭包理解
原创文章,转载请注明:JavaScript中的闭包理解 By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...
- javascript之闭包理解以及应用场景
半个月没写博文了,最近一直在弄小程序,感觉也没啥好写的. 之前读了js权威指南,也写了篇博文,但是实话实说当初看闭包确实还是一头雾水.现在时隔一个多月(当然这一段时间还是一直有在看闭包的相关知识)理解 ...
- JavaScript闭包理解【关键字:普通函数、闭包、解决获取元素标签索引】
以前总觉得闭包很抽象,很难理解,所以百度一下"闭包"概览,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的 ...
- JavaScript ——闭包理解
昨天晚上听别人谈起闭包这个东西,虽然对js有一点了解但却丝毫没有印象,今天也没什么事就顺便研究了一下满足好奇宝宝.整合于网上的理解,记录一下. 一.闭包的作用域 要理解闭包,首先必须理解Javascr ...
- js闭包理解实例小结
Js闭包 闭包前要了解的知识 1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...
- 对于 Javascript 闭包理解
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- JS闭包理解_摘
原文地址1:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html 闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实 ...
- js难点之闭包理解
如何从外部读取局部变量? 闭包就是能够读取其他函数内部变量的函数. 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”. 所以 ...
随机推荐
- JavaScript事件对象与事件处理程序
在学习之前建议请看一下事件流.事件冒泡.事件捕获 一.事件对象 事件对象:在DOM触发事件时,会产生一个事件对象event,这个事件对象包含着所有与事件相关的信息.既然event是事件对象,那么它必然 ...
- js无限级树菜单
以前做网站,树形菜单一般都很简单,自己定义风格样式,简单的js控制,后来原来网上很多文章都在讨论Js树型菜单,看了几个实例,发现这个树比较简单好用. http://hovertree.com/texi ...
- Sharepoint学习笔记—习题系列--70-576习题解析 -(Q109-Q111)
Question 109 Your company uses a third-party service to host its SharePoint 2010 site. The hosting ...
- 在访问jsp时抛java.lang.IllegalArgumentException: Page directive: invalid value for import的原因
问题:java.lang.IllegalArgumentException: Page directive: invalid value for import 环境:tomcat 7.0.65 出错原 ...
- weblogic安装注意事项_linux
➠更多技术干货请戳:听云博客 一.安装过程:参考“weblogic安装截屏(linux)” 注意事项:安装weblogic时,需要注意以下两点: 1.首先在安装目录下创建weblogic12文件夹 如 ...
- 初识JAVA之OOP
有一段时间没发博客了,每次手打还是很累,但感觉很充实.. 最近发现很多初学者到了面向对象编程这个知识点时,不太清楚类是如何转化成为对象的,很是困扰,今天我在这里谈谈我的理解,大家一起来研究学习... ...
- Android中Listview展示及其优化好处
展示效果: 中间的item条目是可以上下滑动的. 代码实现: @Override public View getView(int position, View convertView, ViewGro ...
- web.xml 中的listener、 filter、servlet 加载顺序及其详解
在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰. 首先可以肯定的是 ...
- git之四
1.管理修改 Git与其他版本控制系统相比,Git跟踪并管理的是修改,而非文件. 为什么说Git管理的是修改,而不是文件.接下来做测试,我们对readme.txt修改,追加一行内容: echo &qu ...
- linux 安装tomcat中间件
1.首先确认是否已安装jdk.配置好所需要的环境变量,如果未安装好,则需要安装jdk和配置好正确的环境变量. 检查是否安装jdk及环境变量配置:#java -version. 2.如上述安装并配置正确 ...