如何在 C# 中使用闭包

2025年2月5日 | 阅读 4 分钟

在本文中,我们将讨论如何在 C# 中使用闭包。闭包通常只在函数式编程语言的上下文中可用,但也可以在脚本语言中找到。绑定形成闭包,闭包反过来又在其他环境级别之间保持函数引用,以便函数可以使用外部环境中的声明。C# 中的闭包是使用 lambda 表达式和委托以匿名方式表达的。因此,作用域机制是通过块中函数的功能实现的,作用域定义和临时值都放置在该块中。

什么是 C# 中的闭包?

C# 中的闭包是一个函数或 lambda 表达式,它保留了外层作用域的环境变量,这使得一些程序员采用函数式编程风格 (FSC)。当我们处理像并发编程、事件处理程序和函数式编程这样的问题时,最需要这种理念。

封装可以指将变量与外部世界隔离开来,并将它们链接起来形成一组组件,这些组件也可以用来获取外部数据。

理解概念

为了更好地理解这个概念,我们将更仔细地研究它们的一些基本特征。

  1. 函数或 Lambda 表达式:通常,闭包是具有封装功能的函数和 lambda 表达式。
  2. 捕获的变量:闭包包含一个局部变量数组;因此,它们维持了外部作用域对该变量的可见性或访问权限。
  3. 外层作用域:闭包的作用域表示闭包被声明的地方,以及它将变量转换成闭包的地方。
  4. 生命周期延长:数字环境通过存储在循环块中生命周期超过其正常范围的变量的生命周期来创建这种错觉。

闭包是如何实现的?

当编译器看到我们在一个函数内部并且正在访问来自“上层作用域”的变量时,它会创建一个记录,其中存储了该函数和来自“上层作用域”的变量(通常称为“捕获的变量”)。

闭包作为 C# 中的一等函数

闭包被称为将自由变量绑定到其词法环境的第一个函数。C# 认为原始操作与原始类型相似。这意味着我们可以像修改、调用或传递原始数据类型一样修改、调用或传递函数。因此,闭包可以捕获与其环境相关的变量。但是,这些变量不一定需要隐式地存在于环境中。

C# 闭包是如何工作的?

当 C# 编译器发现一个创建了跨越当前作用域的闭包的委托时,编译器会生成一个编译器生成的类,该类包含该委托及其相关的局部变量。这只是编译器魔法,将在编译器生成的类实例之间移动,每次调用委托时,都会调用该类中的一个内部函数。内存管理的另一个案例是,当不再有对此类实例的引用时,它会被 GC(垃圾回收器)回收,这与回收其他引用的过程相同。

示例

让我们举个例子来说明如何在 C# 中使用闭包。

输出

 
17
84
1
3   

说明

在这个例子中,我们在局部变量 num 上声明了一个闭包。printNum 函数包含一个自定义委托,例如 num。当调用 printNum 时,它会打印出 num 的值,该值被定义为 17。在这里,创建了一个闭包,它不仅传递了局部变量 num,还传递了函数参数 res。委托将这两个变量都闭包起来,并保留对它们的引用。在执行 addNum 期间,当它以参数 67 被调用时,它会将 num 的当前值 17 与给定的参数相加,并返回结果,即 84。当在循环内部创建闭包时,它就变成了一个闭包。对于每次迭代中的 i,delayMethod 委托都会捕获这个循环变量。通过调用 delayMethod,它会显示在调用时刻捕获的当前值。在第一次迭代中,i 是 1。因此,它打印 1。之后,可以在每次迭代中返回对变量 i 的访问,使其能够在每次迭代中打印正确的值。

结论

总之,C# 中的闭包是保留外部作用域环境变量的方法或 lambda 表达式。它们适用于多种场合,例如并发、事件处理和函数式编程。C# 中的闭包可以使用匿名方法、lambda 表达式和委托来实现。通常,C# 中的闭包是封装功能和保留对来自外层作用域的变量的访问权限的强大工具。它们在不同的编程情况下通常很有用,以保持代码的可读性和可维护性。