C# 中的闭包

文章目录

  • 前言
  • 一、闭包的基本概念
  • 二、匿名函数中的闭包
    • 1、定义和使用匿名函数
    • 2、匿名函数捕获外部变量
    • 3、闭包的生命周期
  • 三、Lambda 表达式中的闭包
    • 1、定义和使用 Lambda 表达式
    • 2、Lambda 表达式捕获外部变量
    • 3、闭包的作用域
  • 四、闭包的应用场景
    • 1、事件处理
    • 2、异步编程
    • 3、迭代器和 LINQ 查询
  • 五、闭包的注意事项
    • 1、变量捕获的副作用
    • 2、闭包的性能影响
    • 3、闭包的内存管理
  • 六、总结


前言

  在 C# 中,闭包是一个强大的概念,它允许函数捕获外部变量并在函数外部访问这些变量。闭包在很多场景下都非常有用,比如在匿名函数、Lambda 表达式和委托中。本教程将详细介绍 C# 中的闭包。
在这里插入图片描述

一、闭包的基本概念

  闭包是一种将函数与其周围的环境(即外部变量)封装在一起的技术。在 C# 中,闭包通常是通过匿名函数或 Lambda 表达式实现的。当一个匿名函数或 Lambda 表达式引用了外部变量时,这个变量就被 “捕获” 到了闭包中,并且可以在函数内部访问和修改。

二、匿名函数中的闭包

1、定义和使用匿名函数

delegate int AnonFunc();
AnonFunc func = delegate()
{return 10;
};

  匿名函数是一种没有名称的函数,它可以在代码中直接定义并使用。在 C# 中,匿名函数通常使用delegate关键字或 Lambda 表达式来定义。例如:
  在这个例子中,我们定义了一个匿名函数,并将其赋值给一个委托变量。这个匿名函数没有参数,并且返回值为 10。

2、匿名函数捕获外部变量

  匿名函数可以捕获外部变量,并在函数内部访问和修改这些变量。例如:

int x = 5;
delegate int AnonFunc();
AnonFunc func = delegate()
{return x;
};

  在这个例子中,匿名函数捕获了外部变量x,并在函数内部返回了这个变量的值。

3、闭包的生命周期

delegate int AnonFunc();
int x = 5;
AnonFunc func = delegate()
{return x;
};
x = 10;
Console.WriteLine(func());

  闭包的生命周期与捕获它的委托或 Lambda 表达式的生命周期相同。这意味着,只要委托或 Lambda 表达式存在,闭包就存在,并且可以访问和修改捕获的变量。例如:
  在这个例子中,我们首先定义了一个匿名函数,它捕获了外部变量x。然后,我们修改了变量x的值,并调用了匿名函数。由于闭包的存在,匿名函数返回了修改后的变量x的值。

三、Lambda 表达式中的闭包

1、定义和使用 Lambda 表达式

  Lambda 表达式是一种简洁的匿名函数语法,它可以在代码中直接定义并使用。在 C#中,Lambda 表达式通常使用=>运算符来定义。例如:

   Func<int> func = () => 10;

  在这个例子中,我们定义了一个 Lambda 表达式,并将其赋值给一个委托变量。这个 Lambda 表达式没有参数,并且返回值为 10。

2、Lambda 表达式捕获外部变量

int x = 5;
Func<int> func = () => x;

  Lambda 表达式可以捕获外部变量,并在函数内部访问和修改这些变量。例如:
  在这个例子中,Lambda 表达式捕获了外部变量x,并在函数内部返回了这个变量的值。

3、闭包的作用域

  闭包中的变量的作用域与捕获它的 Lambda 表达式的作用域相同。这意味着,只要 Lambda 表达式存在,闭包就存在,并且可以访问和修改捕获的变量。例如:

int x = 5;Func<int> func = () => x;x = 10;Console.WriteLine(func());

  在这个例子中,我们首先定义了一个 Lambda 表达式,它捕获了外部变量x。然后,我们修改了变量x的值,并调用了 Lambda 表达式。由于闭包的存在,Lambda 表达式返回了修改后的变量x的值。

四、闭包的应用场景

1、事件处理

Button button = new Button();
int count = 0;
button.Click += (sender, e) =>
{count++;Console.WriteLine($"Button clicked {count} times.");
};

  闭包在事件处理中非常有用,因为它可以捕获事件发生时的上下文信息。例如,在 WPF 或 WinForms 应用程序中,我们可以使用闭包来处理按钮点击事件,并访问按钮的属性或其他上下文信息。例如:
  在这个例子中,我们使用闭包来处理按钮的点击事件。闭包捕获了外部变量count,并在每次按钮点击时增加这个变量的值,并在控制台上输出点击次数。

2、异步编程

  闭包在异步编程中也非常有用,因为它可以捕获异步操作发生时的上下文信息。例如,在使用asyncawait关键字进行异步编程时,我们可以使用闭包来访问异步操作的结果或其他上下文信息。例如:

   async Task<int> GetDataAsync(){await Task.Delay(1000);return 10;}int x = 5;Func<int> func = async () =>{int data = await GetDataAsync();return x + data;};int result = await func();Console.WriteLine(result);

  在这个例子中,我们使用闭包来访问异步操作的结果。闭包捕获了外部变量x,并在异步操作完成后将其与异步操作的结果相加,并返回结果。

3、迭代器和 LINQ 查询

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
int sum = 0;
foreach (int number in numbers)
{sum += number;
}
Console.WriteLine(sum);

  闭包在迭代器和 LINQ 查询中也非常有用,因为它可以捕获迭代器或查询的上下文信息。例如,在使用foreach循环或 LINQ 查询时,我们可以使用闭包来访问迭代器或查询的当前元素或其他上下文信息。例如:
  在这个例子中,我们使用foreach循环来遍历一个整数列表,并将每个元素累加到一个变量中。在循环内部,我们使用闭包来捕获外部变量sum,并在每次迭代时将当前元素累加到这个变量中。

五、闭包的注意事项

1、变量捕获的副作用

  闭包捕获外部变量可能会导致一些意想不到的副作用。例如,如果捕获的变量是一个引用类型,并且在闭包内部修改了这个变量的值,那么这个修改可能会影响到其他地方对这个变量的引用。例如:

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };Func<List<int>> func = () => numbers;numbers.Add(6);Console.WriteLine(func().Count);

  在这个例子中,我们定义了一个闭包,它捕获了外部变量numbers。然后,我们在闭包外部修改了这个变量的值,并调用了闭包。由于闭包捕获了外部变量,所以闭包返回的列表也包含了修改后的元素。

2、闭包的性能影响

  闭包可能会对性能产生一些影响,因为它们需要捕获外部变量并在堆上分配内存。在一些性能敏感的场景下,我们可能需要考虑避免使用闭包或者使用其他技术来替代闭包。例如,在一些高性能的计算场景下,我们可以使用结构体而不是类来避免闭包的性能开销。

3、闭包的内存管理

  闭包可能会导致内存泄漏,因为它们可能会捕获外部变量并保持对这些变量的引用。在一些长时间运行的应用程序中,我们需要注意闭包的内存管理,避免不必要的内存泄漏。例如,在使用事件处理时,我们需要注意在不再需要事件处理时取消订阅事件,以避免闭包的内存泄漏。

六、总结

  闭包是 C# 中一个强大的概念,它允许函数捕获外部变量并在函数外部访问这些变量。闭包在很多场景下都非常有用,比如在匿名函数、Lambda 表达式和委托中。在使用闭包时,我们需要注意变量捕获的副作用、性能影响和内存管理等问题,以确保代码的正确性和性能。
在这里插入图片描述

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

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

相关文章

视阅口译与其他口译的不同点

与其他口译不同 译员在进行视阅口译时可以看到书面材料&#xff0c;这与交替口译和同声口译有所不同。译员能够提前浏览文本内容&#xff0c;对主题、结构和专业词汇等有初步的了解。 压力相对较小 视阅口译相较于同声传译而言&#xff0c;时间压力没有那么紧迫。译员有一定…

初学stm32 --- NVIC中断

目录 STM32 NVIC 中断优先级管理 NVIC_Type: ISER[8]&#xff1a; ICER[8]&#xff1a; ISPR[8]&#xff1a; ICPR[8]&#xff1a; IABR[8]&#xff1a; IP[240]&#xff1a; STM32 的中断分组&#xff1a; 中断优先级分组函数 NVIC_PriorityGroupConfig 中断初始化函…

Dot Foods EDI 需求分析及对接流程

Dot Foods 是一家美国领先的食品和非食品产品的中间批发分销商&#xff0c;主要为食品服务、零售和分销行业的客户提供服务&#xff0c;是北美大型食品中间分销商之一。Dot Foods &#xff08;以下简称 Dot&#xff09;的业务模式是通过整合多个供应商的产品&#xff0c;为客户…

MyBatis-Plus(一)

一、 MyBatis-Plus简介 1、简介 MyBatis-Plus &#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为 简化开发、提高效率而生。Mybatis-Plus提供了通用的Mapper和Service&#xff0c;可以在不编写任何SQ…

跟着AI 学AI开发二,本地部署自己的Chat GPT

这里要安装的是Open Web UI &#xff0c;用一张架构图说明AI 前端与后端的关系。 之前的Python 的方法已经做过多次介绍&#xff0c;这里不做赘述。 顺序&#xff1a;1&#xff0c;Ollama。 2&#xff0c;Docker。 3&#xff0c;Open WebUI。 Ollama 安装下载地址&#xff1…

204页PPT金税四期监管要求与最新政策及风险防范-培训课件

这份资料是关于金税四期监管要求、最新政策及风险防范的培训课件&#xff0c;包含204页PPT内容。核心内容涉及金税四期的发展历程、与金税三期的主要变化、指挥决策系统、税务风险预警指标、重点监控行为、税务稽查重点领域、避税方法及处罚、以及企业自查和税务风险管控原理。…

线性规划中的几种逻辑表达式

线性规划中的几种逻辑表达式 注意&#xff1a; 摘录字刘博士的《数学建模与数学规划》&#xff0c; 以便用时可查。 实际上Gurobi API 中自身放啊变的逻辑表达式函数&#xff0c;下面列出自定义的实现方式。 1 逻辑与 如果 x 1 1 x_1 1 x1​1, x 2 1 x_2 1 x2​1, 那…

knife4j增强swagger

背景 swagger很好用&#xff0c;但是UI不够友好 导入maven依赖 使用maven-search在common模块中导入依赖 <!-- knife4j --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId&g…

iOS - 超好用的隐私清单修复脚本(持续更新)

文章目录 前言开发环境项目地址下载安装隐私访问报告隐私清单模板最后 前言 在早些时候&#xff0c;提交应用到App Store审核&#xff0c;大家应该都收到过类似这样的邮件&#xff1a; Although submission for App Store review was successful, you may want to correct th…

【WRF教程第四期】WRF 初始化概述:以4.5版本为例

WRF 初始化&#xff08;WRF Initialization&#xff09; Building Initialization Programs编译方式 理想案例初始化&#xff08;Initialization for Idealized Cases&#xff09;理想化案例的输入可用的理想化案例 现实案例初始化&#xff08;Initialization for Real Data Ca…

测试工程师八股文04|计算机网络 和 其他

一、计算机网络 1、http和https的区别 HTTP和HTTPS是用于在互联网上传输数据的协议。它们都是应用层协议&#xff0c;建立在TCP/IP协议栈之上&#xff0c;用于客户端&#xff08;如浏览器&#xff09;和服务器之间的通信。 ①http和https的主要区别在于安全性。http是一种明…

【C++】inline函数(内联函数)

文章目录 前言一、宏函数的缺陷二、inline函数1.inline函数的展开规则2.inline的设计分析3.inline函数不建议声明和定义分离 前言 C程序频繁调用函数会使代码效率降低&#xff0c;因为创建函数栈帧需要消耗时间。于是C语言引入宏函数的概念&#xff0c;使用宏函数来替代一些功能…

Android OpenGLES2.0开发(九):图片滤镜

“当你改变想法的时候&#xff0c;记得也要改变你的世界。”——诺曼文森特皮尔 Android OpenGLES开发&#xff1a;EGL环境搭建Android OpenGLES2.0开发&#xff08;一&#xff09;&#xff1a;艰难的开始Android OpenGLES2.0开发&#xff08;二&#xff09;&#xff1a;环境搭…

易语言OCR证件照文字识别

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

指针练习题15道【C语言】

1.利用指针变量将一个数组中的数据反向输出。 声明&#xff1a; void work1(int *, int); // 声明反向遍历 void work1_1(int *, int); // 声明正向遍历实现&#xff1a; // 利用指针变量将一个数组中的数据反向输出&#xff0c;反向遍历 void work1( int *p,int len) {p (…

单节点calico性能优化

在单节点上部署calicov3273后&#xff0c;发现资源占用 修改calico以下配置是资源消耗降低 1、因为是单节点&#xff0c;没有跨节点pod网段组网需要&#xff0c;禁用overlay方式网络(ipip&#xff0c;vxlan),使用route方式网络 配置calico-node的环境变量 CALICO_IPV4POOL_I…

在 Spring Boot 3 中实现基于角色的访问控制

基于角色的访问控制 (RBAC) 是一种有价值的访问控制模型,可增强安全性、简化访问管理并提高效率。它在管理资源访问对安全和运营至关重要的复杂环境中尤其有益。 我们将做什么 我们有一个包含公共路由和受限路由的 Web API。受限路由需要数据库中用户的有效 JWT。 现在用户…

电子系统中用于降噪的接地

当接地系统中存在EMI、RFI 或由焊机、变速驱动器、电器等引起的电脉冲等干扰时&#xff0c;它们会在中性线和接地之间产生共模噪声&#xff0c;可能会影响电子设备。 国家电气规范 (NEC) 允许安装隔离接地插座 (IG)&#xff0c;即磁轭和接地端子之间没有连接。轭是插座后面的金…

SmartX分享:SMTX ZBS 中 RDMA 技术简介

目录 背景如何实现存储网络是什么TCP/IPRDMARDMA 工作原理RDMA 的实现方案 ZBS 支持 RDMA 的要求 参考 背景 我们清楚&#xff0c;分布式存储将利用网络作不同设备的互联。最基础的如TCP/IP的IP SAN&#xff0c;进阶的有FC SAN、IB等等。 SmartX 支持 10G以上的TCP/IP网络作为…

《Vue3实战教程》5:响应式基础

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 响应式基础​ API 参考 本页和后面很多页面中都分别包含了选项式 API 和组合式 API 的示例代码。现在你选择的是 组合式 API。你可以使用左侧侧边栏顶部的“API 风格偏好”开关在 API 风格之间切换。 声明响应式状态…