C# 中的闭包

news2025/7/17 0:23:10

文章目录

  • 前言
  • 一、闭包的基本概念
  • 二、匿名函数中的闭包
    • 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.coloradmin.cn/o/2261611.html

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

相关文章

ChatGPT客户端安装教程(附下载链接)

用惯了各类AI的我们发现每天打开网页还挺不习惯和麻烦&#xff0c;突然发现客户端上架了&#xff0c;懂摸鱼的人都知道这里面的道行有多深&#xff0c;话不多说&#xff0c;开整&#xff01; 以下是ChatGPT客户端的详细安装教程&#xff0c;适用于Windows和Mac系统&#xff1a…

GRE over IPSec 如何应用?如何在ensp上配置GRE over IPSec 实验?

GRE over IPSec应用场景 IPSec VPN本端设备无法感知对端有几个设备 &#xff0c;本端共用一个IPSec SA 。报文封装中没有对端设备的下一跳 &#xff0c;所以无法传输组播、广播和非IP报文 &#xff0c;比如OSPF协议 &#xff0c;导致分支与总部的内部网络之间无法使用OSPF路由…

概率论得学习和整理29: 用EXCEL 描述二项分布

目录 1 关于二项分布的基本内容 2 二项分布的概率 2.1 核心要素 2.2 成功K次的概率&#xff0c;二项分布公式 2.3 期望和方差 2.4 具体试验 2.5 概率质量函数pmf 和cdf 3 二项分布的pmf图的改进 3.1 改进折线图 3.2 如何生成这种竖线图呢 4 不同的二项分布 4.1 p0.…

leetcode 面试经典 150 题:三数之和

链接三数之和题序号11类型数组解题方法排序双指针法难度中等 题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c; 同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三…

【Linux】Nginx一个域名https一个地址配置多个项目【项目实战】

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

【线性代数】理解矩阵乘法的意义(点乘)

刚接触线性代数时&#xff0c;很不理解矩阵乘法的计算规则&#xff0c;为什么规则定义的看起来那么有规律却又莫名其妙&#xff0c;现在参考了一些资料&#xff0c;回过头重新总结下个人对矩阵乘法的理解&#xff08;严格来说是点乘&#xff09;。 理解矩阵和矩阵的乘法&#x…

HTML、CSS表格的斜表头样式设置title 画对角线

我里面有用到layui框架的影响&#xff0c;实际根据你自己的框架来小调下就可以 效果如下 上代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…

29. Three.js案例-自定义平面图形

29. Three.js案例-自定义平面图形 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它利用 WebGL 技术在浏览器中渲染 3D 图形。 构造器 THREE.WebGLRenderer(parameters : object) 参数类型描述parametersobject可选参数对象&…

一条线上的点

给你一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 提示&#xff1a; 1 < points.length < 300points[i].length 2-104 < xi, yi < 104points 中的所有点 互不相同 解析&#xff1a;使用斜…

WebRTC服务质量(05)- 重传机制(02) NACK判断丢包

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

八股—Java基础(二)

目录 一. 面向对象 1. 面向对象和面向过程的区别&#xff1f; 2. 面向对象三大特性 3. Java语言是如何实现多态的&#xff1f; 4. 重载&#xff08;Overload&#xff09;和重写&#xff08;Override&#xff09;的区别是什么&#xff1f; 5. 重载的方法能否根据返回值类…

linux ibus rime 中文输入法,快速设置为:默认简体 (****)

本文环境&#xff1a; ubuntu 22.04 直接 apt install ibus-rime 输入法的安全性&#xff0c;人们应该关注吧&#xff01;&#xff01;&#xff1f;&#xff1f; 云输入法&#xff1f;将用户的输入信息传输到云端吗&#xff1f;恐怕很多人的银行账户和密码&#xff0c;早就上…

uniapp使用百度地图配置了key,但是显示Map key not configured

搞了我两天的一个问题。 hbuilderx版本&#xff1a;4.36 问题介绍&#xff1a; 我的项目是公司的项目&#xff0c;需要在H5端使用百度地图&#xff0c;使用vue-cli创建的uniapp&#xff0c;就是uni代码在src里的目录结构。就是使用这种方式才会遇到这个问题。 问题原因&#xf…

ensp 静态路由配置

A公司有广州总部、重庆分部和深圳分部3个办公地点&#xff0c;各分部与总部之间使用路由器互联。广州、重庆、深圳的路由器分别为R1、R2、R3&#xff0c;为路由器配置静态路由&#xff0c;使所有计算机能够互相访问&#xff0c;实训拓扑图如图所示 绘制拓扑图 给pc机配置ip地址…

3分钟读懂数据分析的流程是什么

数据分析是基于商业目的&#xff0c;有目的地进行收集、整理、加工和分析数据&#xff0c;提炼出有价值的 信息的一个过程。整个过程大致可分为五个阶段&#xff0c;具体如下图所示。 1.明确目的和思路 在开展数据分析之前&#xff0c;我们必须要搞清楚几个问题&#xff0c;比…

Python-基于Pygame的小游戏(坦克大战-1.0(世界))(一)

前言:创作背景-《坦克大战》是一款经典的平面射击游戏&#xff0c;最初由日本游戏公司南梦宫于1985年在任天堂FC平台上推出。游戏的主题围绕坦克战斗&#xff0c;玩家的任务是保卫自己的基地&#xff0c;同时摧毁所有敌人的坦克。游戏中有多种地形和敌人类型&#xff0c;玩家可…

认识漏洞-GIT泄露漏洞、APP敏感信息本地存储漏洞

为方便您的阅读&#xff0c;可点击下方蓝色字体&#xff0c;进行跳转↓↓↓ 01 [GIT泄露漏洞&#xff0c;你检查了吗&#xff1f;](https://mp.weixin.qq.com/s/I69Jsu8GfX9FJIhMVFe_fA)02 [APP客户端评估- 敏感信息本地存储]( https://mp.weixin.qq.com/s/IrTLZp_lslvGaD4Xhlk…

《Kali 系统中 Docker 镜像加速器安装指南:加速容器镜像拉取》

在 Kali 中配置 Docker 镜像加速器可以显著提高拉取 Docker 镜像的速度&#xff0c;以下是具体步骤&#xff1a; 一、获取镜像加速器地址 国内有许多云服务提供商提供镜像加速器服务&#xff0c;例如阿里云、腾讯云、网易云等。以阿里云为例&#xff0c;你需要先在阿里云容器镜…

allure报告环境搭建

1、allure下载新版.zip文件&#xff0c;解压 https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/ 2、解压后放到d盘文件里&#xff1a;、 3、环境变量配置bin文件和jre文件 4、虚拟环境里安装allure-pytest&#xff0c;cmd执行activate.bat,进入对应…

MVC基础——市场管理系统(四)

文章目录 项目地址六、EF CORE6.1 配置ef core环境6.2 code first6.2.1 创建Database context1. 添加navigation property2. 添加MarketContext上下文七、Authentication7.1 添加Identity7.2 Run DB migration for Identity7.3 使用Identity7.3.1 设置认证中间件7.3.2 设置权限…