C#中的闭包和意想不到的坑

虽然闭包主要是函数式编程的玩意儿,而C#的最主要特征是面向对象,但是利用委托或lambda表达式,C#也可以写出具有函数式编程风味的代码。同样的,使用委托或者lambda表达式,也可以在C#中使用闭包。

根据WIKI的定义,闭包又称语法闭包或函数闭包,是在函数式编程语言中实现语法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。闭包也可以延迟变量的生存周期。

嗯。。看定义好像有点迷糊,让我们看看下面的例子吧

e394849fedc5f0f64e51a0df347aad29.png

这个例子非常简单,用lambda表达式创建一个Action对象,之后再调用这个Action对象。但是仔细观察会发现,当Action对象被调用的时候,CreateGreeting方法已经返回了,作为它的实参的message应该已经被销毁了,那么为什么我们在调用Action对象的时候,还是能够得到正确的结果呢?

原来奥秘就在于,这里形成了闭包。虽然CreateGreeting已经返回了,但是它的局部变量被返回的lambda表达式所捕获,延迟了其生命周期。怎么样,这样再回头看闭包定义,是不是更清楚了一些?

闭包就是这么简单,其实我们经常都在使用,只是有时候我们都不自知而已。比如大家肯定都写过类似下面的代码。

e4d3133271115cc05b862cf84a0d46b5.png

这里的代码其实就用了闭包,因为我们可以肯定,在control被点击的时候,这个message早就超过了它的声明周期。合理使用闭包,可以确保我们写出在空间和时间上面解耦的委托。

不过在使用闭包的时候,要注意一个陷阱。因为闭包会延迟局部变量的生命周期,在某些情况下程序产生的结果会和预想的不一样。让我们看看下面的例子。

a7123fcb8e3c793ae4ee8c16964e5c94.png

这个例子也非常简单,创建一个Action链表并依次执行它们。看看结果

0f06783bf4b97ea524927860f83e6081.png7e3d7330467ba391e93d27886386a4f4.png

相信很多人看到这个结果的表情是这样的!!难道不应该是0,1,2,3,4吗?出了什么问题?

刨根问底,这儿的问题还是出现在闭包的本质上面,作为“闭包延迟了变量的生命周期”这个硬币的另外一面,是一个变量可能在不经意间被多个闭包所引用。

在这个例子里面,局部变量i同时被5个闭包引用,这5个闭包共享i,所以最后他们打印出来的值是一样的,都是i最后退出循环时候的值5。

要想解决这个问题也很简单,多声明一个局部变量,让各个闭包引用自己的局部变量就可以了。    

8af2b91cca40505b696407f00ee0a864.png

d951169095c051e17b12c7f18a49dd71.png

这样各个闭包引用不同的局部变量,刚刚的问题就解决了。

除此之外,还有一个修复的方法,在创建闭包的时候,使用foreach而不是for。至少在C# 7.0 的版本上面,这个问题已经被注意到了,使用foreach的时候编译器会自动生成代码绕过这个闭包陷阱。

06d6467016fbe080c728b33bed80763c.png

这就是在闭包在C#中的使用和其使用中的一个小陷阱,希望大家能通过老胡的文章了解到这个知识点并且在开发中少走弯路!

5454a2a33f3fe6ef18198a4dd0ab9ab6.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285978.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

投票彰显电信合约机诺基亚Lumia 800C受热捧

49元可以做什么?与朋友吃顿便饭、买几包好烟,同时也能参加中国电信Lumia 800C的合约购机计划,其中选择49元是最低套餐,选择并预存600元话费,便可以以2999元购买Lumia 800C。 对于Lumia 800C,它可是新一代诺…

07查询表达式 及 page分页、order 排序《ThinkPHP6 入门到电商实战》

文章目录(更新中…) 01 thinkphp6的前期开发准备《ThinkPHP6 入门到电商实战》 02 控制器《ThinkPHP6 入门到电商实战》 03 数据库查询、模型查询、多库查询《ThinkPHP6 入门到电商实战》 04 tp6 的查数据《ThinkPHP6 入门到电商实战》 05 tp6 的数据添…

基于netty的微服务架构

基于netty的微服务架构 微服务一篇好文章 http://san-yun.iteye.com/blog/1693759 教程 http://udn.yyuap.com/doc/essential-netty-in-action/GETTING%20STARTED/Introducing%20Netty.html netty原理 http://www.infoq.com/cn/articles/netty-server-create netty方面专家 李林…

无人机模拟操控凤凰模拟器(PhoenixRC 5.0)安装及配置图文教程(附凤凰模拟器下载地址)

文章目录 1. 凤凰模拟器简介2. 凤凰模拟器安装及配置图文教程3. 凤凰模拟器下载地址1. 凤凰模拟器简介 凤凰phoenixrc模拟器(航模8合1模拟器)是一款专业的飞行模拟器软件,它是属于航模新手练模拟专用,可模拟大疆无人机,各种穿越机,还有很多固定翼和直升机等等。凤凰模拟操…

NCF 的Dapr应用实例的运行

简介在进行今天的主要内容之前,先带大家了解一下DaprDapr 是一个可移植的、事件驱动的运行时,它使任何开发人员都可以轻松构建在云和边缘上运行的弹性、无状态和有状态的应用程序,并包含语言和开发人员框架的多样性。任何语言,任何…

06 tp6 的数据更新(改)及删除 《ThinkPHP6 入门到电商实战》

文章目录(更新中…) 01 thinkphp6的前期开发准备《ThinkPHP6 入门到电商实战》 02 控制器《ThinkPHP6 入门到电商实战》 03 数据库查询、模型查询、多库查询《ThinkPHP6 入门到电商实战》 04 tp6 的查数据《ThinkPHP6 入门到电商实战》 05 tp6 的数据添…

2020年:风雨兼程,不负韶华,注定是不平凡的一年

时光易逝,岁月不老。2020,发生了太多的惊喜。 文章目录小瑶瑶报到疫情防控,我们是认真的感谢CSDN一路相伴小瑶瑶报到 1月20日,闺女小瑶瑶已超过预产期一周了,决定入院进行手术,次日,手术顺利进…

Python对文件的操作(转)

一、文件对象 我理解的文件对象就是一个接口&#xff0c;通过这个接口对文件进行相关操作。 《Python 核心编程》上说的很晦涩&#xff0c;这里没有深刻理解到&#xff0c;希望有人能解释给我听。>>> f open(demo.txt,r) >>> f <open file demo.txt, mod…

微软发布全新Win11 轻量级系统Validation OS

你可能还不知道&#xff0c;在没有任何公开宣传的情况下&#xff0c;在最近&#xff0c;微软最近发布了一个全新的操作系统 Microsoft Validation OS。根据微软的说法&#xff0c;这是一个轻量级、快速且可自定义的基于 Windows 11 的操作系统。专门为硬件或软件供应商、开发人…

CSDN博客文章阅读模式插件(附源码)

插件地址&#xff1a;https://greasyfork.org/zh-CN/scripts/380667-csdn%E5%8D%9A%E5%AE%A2%E9%98%85%E8%AF%BB%E6%A8%A1%E5%BC%8F%E5%88%87%E6%8D%A2%E6%8F%92%E4%BB%B6 插件安装使用说明请参阅&#xff1a;https://greasyfork.org/zh-CN 浏览器&#xff08;正常&#xff09…

【ArcGIS风暴】ArcGIS tif转jpg:JPEG压缩仅支持8位或16位无符号数据(具有一个或三个波段,且没有色彩映射表)解决方案!

扩展阅读:【ArcGIS风暴】ArcGIS支持的栅格数据格式大全及格式转换案例精解 文章目录 问题描述tif格式和JPEG格式详解ArcGIS软件tif转jpg方法总结问题描述 如下图所示,在ArcGIS中将tif格式的无人机影像数据导出为Jpg格式时,提示:JPEG压缩仅支持8位或16位无符号数据(具有一…

Blazor University (29)表单 —— 编辑表单数据

原文链接&#xff1a;https://blazor-university.com/forms/editing-form-data/编辑表单数据源代码[1]因为 EditForm 组件呈现标准的 <form> HTML 元素&#xff0c;实际上可以在我们的标记中使用标准的 HTML 表单元素&#xff0c;例如 <input> 和 <select>&a…

广州Uber优步司机奖励政策(1月4日~1月10日)

滴快车单单2.5倍&#xff0c;注册地址&#xff1a;http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单&#xff1a;http://www.cnblogs.com/mfryf/p/4612609.html 优步奖励低/不挣钱/怎么办?看这里&#xff1a;http://www.cnblogs.com/mfry…

10 关联模型《ThinkPHP6 入门到电商实战》

一、什么是关联模型 关联模型指在 tp 中使用模型对多个数据表进行关联。例如一个主账户表与一个账户信息表进行关联&#xff0c;此时两者关联后可以更加简便的进行操作&#xff0c;使代码更加清晰&#xff0c;操作更加简便。 二、 正向一对一关联 一对一关联指的是数据只有一…

Android 整体设计及背后意义

目录 1. Android设计的现实意义 1.1 发展的前提&#xff1a;硬件抽象 1.2 能力的枢纽&#xff1a;组件化 1.3 应用的基础-接口层 2. 对于我们的象征意义和实践 3. 小结 阿里妹导读&#xff1a;现实工作中经常可以听到这样的说法&#xff1a;框架的升级带来协议性能的提升…

85、交换机安全MAC层***配置实验之Port-Security

1、Port Security解析触发Port Security的条件&#xff1a;未授权的MAC地址端口MAC地址数量超过了限制触发Port Security后的动作&#xff1a;protect Security violation protect mode 丢弃数据&#xff0c;不发送SNMP Trap消息 restrict Security violation restr…

11 验证器《ThinkPHP6 入门到电商实战》

注&#xff1a;示例来源于官方手册 一、验证器定义 验证器用于对数据进行验证&#xff0c;你可以理解为一个“层”&#xff0c;在传入数据时可以使用这个层对数据进行验证&#xff0c;这样就可以不用频繁的在方法中编写代码去验证&#xff0c;只需要编写一个验证层即可&#…

nginx+php

nginxphp基础架构 生产实践 nginx配置文件: 主配置文件 123456789101112131415161718192021222324252627282930313233[rootlinux-node1 conf.d]# cat /etc/nginx/nginx.conf user nginx;worker_processes auto;error_log /var/log/nginx/error.log; pid /run/nginx.pid; # Load…

【ArcGIS风暴】ArcGIS10.8中栅格数据金字塔的来龙去脉,你知道吗?

如下图所示,通常情况下,当将没有金字塔的栅格数据集添加至 ArcGIS时,系统将提示您构建金字塔。金字塔指不同比例下分辨率降低的数据概视图。金字塔十分有用,因为金字塔提升了分辨率低于其全分辨率的栅格数据集的绘制速度。建议构建用于大型栅格数据集的金字塔。 点击【是】…

斯坦福大学Andrew Ng - 机器学习笔记(8) -- 推荐系统 大规模机器学习 图片文字识别...

大概用了一个月&#xff0c;Andrew Ng老师的机器学习视频断断续续看完了&#xff0c;以下是个人学习笔记&#xff0c;入门级别&#xff0c;权当总结。笔记难免有遗漏和误解&#xff0c;欢迎讨论。 鸣谢&#xff1a;中国海洋大学黄海广博士提供课程视频和个人笔记&#xff0c;在…