C#温故而知新系列 -- 闭包
闭包的由来
要说闭包的由来就不得不先说下函数式编程了。近几年函数式编程也是比较火热,我们先来看看函数式编程的一些基本的特性这个有助于我们理解闭包的由来。
函数式编程
函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念。这里很明显的指出了函数式编程中最重要的就是函数而且是数学中的函数,比如f(x),数学中的函数最大的特点就是只要是同样的参数x那么我的结果必定是相等的,也就是说我们函数的返回值只是依赖于参数而不依赖于其他状态(比如js中的全局变量就是一个干扰因素);后一句中说避免变量的概念,这句话如果从函数式编程来说不太恰当,因为这句话中的函数意思还是我们在编程语言中所使用的变量也就是一个存储单元,而在函数式编程中变量却是数学中变量的定义是一个值得名称。比如,我们最基本的赋值等式 x = x+1,让我们程序员看这是一个简单的赋值代码,而让学数学的人来说这个等式是根本不成立的。 所以我们在函数式编程中是不允许多次赋值的。而这一句话也是讲述了函数式编程好处的最主要的原因:
第一点、函数的结果只依赖于参数而不依赖其他状态,这样写的代码很容易进行推理不容易发生错误,极大的方便的单元测试和调试。
第二点、因为不可变性和无状态,那么我们在处理多个线程之间就不用担心资源的争夺,不需要用锁来保存状态。
高阶函数
函数式编程中函数是一等公民,和我们的口号 "万物皆对象"有点相似,在函数式编程中,我们努力用函数来表达所有的事情,当然我们也需要函数可以传过来传过去这就是高阶函数,也就是把函数作为参数或者返回值,继而实现复用,这样即是可以把复用的粒度降到函数。C#语言中也有类似的东西--委托,当然C#中的函数跟函数式编程中的就不一样了,但是有吸收一些函数式编程语言中的特性,比如C#中lamda,Linq。
关于函数式编程博客园有很多很好的文章介绍我就不详说了,接下来就是引出我们今天的主题--闭包。
因为函数式编程的基础就是Lambda演算,所以这一节演算我们用Lambda演算来带出我们的主题,关于这个演算我也懂得不是太多,想要入门的同学可以看看这个 点这里
首先定义一个简单的演算
λx.λy.x+y
如果x为1 y为2 演算过程则为
((λx.λy.x+y)1)2=(λy.1+y)2=(1+2)=3
接下来我们用到高阶函数
λy . (λx . x + y)
演算过程:
((λy . (λx . x + y))1)2=((λx . x + 1))2 = (2+1)=3
可以看到这个演算中外层函数使用的是内层函数,也就是说使用是一个函数作为了计算结果。OK ,我们把内层函数单独拿出来,(λx . x + y),可以很明显的看到如果脱离的上下文呢,我们的y是没有值的,也就是y是没有绑定的,也可以说y对于我们这个函数是自由的! 如果在函数式编程中,在外层函数执行完毕之后我们的y变量就应该被销毁,那么如果我们在内层函数中如果还需要用到y的话怎么办呢? 对于这个问题,设计者则做了其他的处理:如果一个函数返回另一个函数,而被返回函数又需要外层函数的变量时,不会立即释放这个变量,而是允许被返回的函数引用这些变量。支持这种机制的语言称为支持闭包机制,而这个内部函数连同其自由变量就形成了一个闭包(这句话是摘自其他博客,自己难得整理文字。。。)。这就是我们闭包的由来,而我们其他的语言如果有用到函数式编程的思想,并且允许函数来进行传递就会遇到类似的问题,所以各个语言就需要用其自己的方式来实现闭包!
C#中闭包的实现
从上一节我们也就是能总结出闭包其实就是要执行并且包含自由变量的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境的一个结合。
然后进入我们的C#编程时刻了,我们就用简单的例子来实现,并且查看编译器生成的代码 看看C#中是怎么实现闭包,毕竟我们也是有委托的 。。。
首先写一个简单得不能在简单的代码
1 using System; 2 3 namespace closure 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 Console.WriteLine(test(1)(2)); 10 Console.ReadKey(); 12 } 13 14 public static Func<int,int> test(int x) 15 { 16 //作用域1 17 return (y) => 18 { 19 //作用域2 20 return x + y; 21 }; 22 } 23 } 24 }
可以看到我们test的方法中传入变量x的作用域是在1 在执行匿名函数的时候应该是已经释放在作用域2就不应该存在了,而我们却能准确的得到计算结果
说明我们的变量x确实在作用域2中还存在,接下来我们看看编译器帮我们做了什么事情,
可以看到我们的test方法中多了一个对象 <>c__DisplayClass1_0 class_;这个东西的具体定义是啥?
这个很明显了,其实闭包只是编译器帮我们把自由变量封装到了一个对象中供我们作用域外使用,那我们如果去掉作用域2中使用x变量呢?
编译器原来为了自由变量维护的对象没了 。。。结果在意料之中。
OK,这篇文章就到此结束了,关于闭包是python中啊 js中啊 或者C#中得用处我就不细说了,博客园中有太多太多的介绍了,希望这边文章对你有帮助,欢迎拍砖!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
JVM对异常的默认处理方案
JVM对异常的默认处理方案 1 package cn.itcast_01; 2 3 /* 4 * 异常:程序出现了不正常的情况。 5 * 6 * 举例:今天天气很好,班长出去旅游。骑着自行车,去山里面呼吸新鲜空气。 7 * 问题1:山路塌陷了,班长及时停住了,但是过不去了。严重的问题。 8 * 问题2:班长出门推自行车,发现气没了,把气吹起来。出发前就应该检查的问题。 9 * 问题3:班长骑着车在山路上惬意的行驶着,山路两边是有小石子的,中间是平坦的水泥路。 10 * 一直在平坦的水泥路上行驶是没有任何问题的,但是呢,他偏偏喜欢骑到小石子上,结果爆胎了。旅游的过程中出现的问题。 11 * no zuo no die。 12 * 13 * 程序的异常:Throwable 14 * 严重错误问题:Error 我们不处理。这种问题一般都是很严重的,我们一般处理不了,比如说内存溢出。 15 * 问题:Exception 16 * 运行期问题:RuntimeException 这种问题我们也不处理,因为是你写代码的问题,而且这个问题的出现肯定是我们的代码不够严谨,需要修正代码的。 17 * 编译...
- 下一篇
js知识点清单
js知识点清单 javaweb的js部分 自己总结的知识点清单,如果转发请注明出处,尊重原创,虽然写的不怎么样吧,哈哈 ,内容中有些时候是不连贯的,那是本人做的笔记,或者写的感想,不影响阅读。有错误的地方还请批评指正。 Js部分 Document.write(“ ”) 可以往HTML里面写文字或者标签也可以 对大小写敏感 Alert(内容) 弹出一个对话框 Js事件 1.事件 事件是可以被javascript检测到的行为 2.主要事件 属性 描述 onClick 单击事件 onMouseOver 鼠标胫骨事件 onMouseOut 鼠标移出事件 onChange 文本内容改变事件 onSelect 文本框选中事件 onFocus 光标聚集事件 onBlur 移开光标事件 onload 网页加载事件 onUnload 关闭网页事件 js的DOM对象 1.DOM简介 DOM操作HTML 1) JavaScript能改变页面中的所有HTML元素 2) JavaScript能够改变页面中的所有HTML属性 3) JavaScript能够改变页面中的所有css样式 4) JavaScript能...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果