.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 闭包理解的更多相关文章

  1. javascript闭包理解

    //闭包理解一 function superFun(){ var _super_a='a'; function subfuc(){ console.log(_super_a); } return su ...

  2. JavaScript中的闭包理解

    原创文章,转载请注明:JavaScript中的闭包理解  By Lucio.Yang 1.JavaScript闭包 在小学期开发项目的时候,用node.js开发了服务器,过程中遇到了node.js的第 ...

  3. javascript之闭包理解以及应用场景

    半个月没写博文了,最近一直在弄小程序,感觉也没啥好写的. 之前读了js权威指南,也写了篇博文,但是实话实说当初看闭包确实还是一头雾水.现在时隔一个多月(当然这一段时间还是一直有在看闭包的相关知识)理解 ...

  4. JavaScript闭包理解【关键字:普通函数、闭包、解决获取元素标签索引】

    以前总觉得闭包很抽象,很难理解,所以百度一下"闭包"概览,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的 ...

  5. JavaScript ——闭包理解

    昨天晚上听别人谈起闭包这个东西,虽然对js有一点了解但却丝毫没有印象,今天也没什么事就顺便研究了一下满足好奇宝宝.整合于网上的理解,记录一下. 一.闭包的作用域 要理解闭包,首先必须理解Javascr ...

  6. js闭包理解实例小结

    Js闭包 闭包前要了解的知识  1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取全局变量 <script type="text/javascript"> ...

  7. 对于 Javascript 闭包理解

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...

  8. JS闭包理解_摘

    原文地址1:http://www.cnblogs.com/mzwr1982/archive/2012/05/20/2509295.html 闭包是一个比较抽象的概念,尤其是对js新手来说.书上的解释实 ...

  9. js难点之闭包理解

    如何从外部读取局部变量? 闭包就是能够读取其他函数内部变量的函数. 由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”. 所以 ...

随机推荐

  1. 使用C#类向数据库添加数据的例子源码

    在上一篇中,增加了sql server数据库操作类SqlOperator,用于操作sql server数据库.还有一个SqlStringHelper类,用于处理sql语句的单引号.那么这两个类怎么使用 ...

  2. Pro HTML5 Programming(Second Edition)2.Canvas API(1)

    1.在使用HTML5的Canvas元素时,考虑到有些浏览器不支持canvas元素,或是不支持HTML5 Canvas API中的某些特性,开发人员最好提供一份替代代码. 以下代码展示如何在canvas ...

  3. webpack初入

    序言:前面已经倒腾了grunt.gulp.fis3,今天来通过一个例子玩玩webpack!最终预览 通过下面的例子,能够了解以下几点: 1.如何安装webpack 2.如何使用webpack 3.如何 ...

  4. 【grunt第一弹】30分钟学会使用grunt打包前端代码

    前言 以现在前端js激增的态势,一个项目下来几十个js文件轻轻松松对于复杂一点的单页应用来说,文件上百简直是家常便饭,那么这个时候我们的js文件应该怎么处理呢?另外,对于css文件,又该如何处理呢?? ...

  5. [python]数据整理,将取得的众多的沪深龙虎榜数据整一整

    将昨日取得的众多的沪深龙虎榜数据整一整 提取文件夹内所有抓取下来的沪深龙虎榜数据,整理出沪深两市(含中小创)涨幅榜股票及前5大买入卖出资金净值,保存到csv文件 再手动使用数据透视表进行统计 原始数据 ...

  6. IE7浏览器窗口大小改变事件执行多次bug(转)

    var resizeTimer = null; $(window).resize(function() { if (resizeTimer) clearTimeout(resizeTimer); re ...

  7. 如何基于OM模型使用C#在程序中给SharePoint的BCS外部数据类型的字段赋值

    概述: 外部内容类型和数据,SharePoint从2010这个版本开始就对BCS提供非常强大的支持,点点鼠标就可以取代以前直接编辑XML的方式来设置SharePoint到SQL数据库的连接.非常方便地 ...

  8. iOS程序破解——获取.ipa程序包

    原文在此 首先肯定不是获取自己的ipa包. 为什么要获取ipa包呢?比如,在仿写一些程序时,避免不了获取它的图片素材等等,那么最快也是最有效的方式就是获取原程序的ipa包.更或者,你想要逆向分析某一款 ...

  9. 【原】iOS动态性(四):一行代码实现iOS序列化与反序列化(runtime)

    为取得更好的排版效果,本文同样发布在简书上,强烈建议跳转到[1]http://www.jianshu.com/p/fed1dcb1ac9f 一.变量声明 为便于下文讨论,提前创建父类Biology以及 ...

  10. android四大组件之Broadcast

    广播的概念 现实中:我们常常使用电台通过发送广播发布消息,买个收音机,就能收听 Android:系统在产生某个事件时发送广播,应用程序使用广播接收者接收这个广播,就知道系统产生了什么事件.Androi ...