iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#中闭包概念讲解
  • 785
分享到

C#中闭包概念讲解

2024-04-02 19:04:59 785人浏览 独家记忆
摘要

理解C#中的闭包 1、 闭包的含义 首先闭包并不是针对某一特定语言的概念,而是一个通用的概念。除了在各个支持函数式编程的语言中,我们会接触到它。一些不支持函数式编程的语言中也能支持闭

理解C#中的闭包

1、 闭包的含义

首先闭包并不是针对某一特定语言的概念,而是一个通用的概念。除了在各个支持函数式编程的语言中,我们会接触到它。一些不支持函数式编程的语言中也能支持闭包(如java8之前的匿名内部类)。

在看过的对于闭包的定义中,个人觉得比较清晰的是在《javascript高级程序设计》这本书中看到的。具体定义如下:

闭包是指有权访问另一个函数作用域中的变量的函数。

注意,闭包这个词本身指的是一种函数。而创建这种特殊函数的一种常见方式是在一个函数中创建另一个函数。

2、 在C# 中使用闭包(例子选取自《C#函数式程序设计》)

下面我们通过一个简单的例子来理解C#闭包


class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetClosureFunction()(30));
    }

    static Func<int, int> GetClosureFunction()
    {
        int val = 10;
        Func<int, int> internalAdd = x => x + val;

        Console.WriteLine(internalAdd(10));

        val = 30;
        Console.WriteLine(internalAdd(10));

        return internalAdd;
    }
}

上述代码的执行流程是Main函数调用GetClosureFunction函数,GetClosureFunction返回了委托internalAdd并被立即执行了。

输出结果依次为20、40、60

对应到一开始提出的闭包的概念。这个委托internalAdd就是一个闭包,引用了外部函数GetClosureFunction作用域中的变量val。

注意:internalAdd有没有被当做返回值和闭包的定义无关。就算它没有被返回到外部,它依旧是个闭包。

3、 理解闭包的实现原理

我们来分析一下这段代码的执行过程。在一开始,函数GetClosureFunction内定义了一个局部变量val和一个利用lamdba语法糖创建的委托internalAdd。

第一次执行委托internalAdd 10 + 10 输出20

接着改变了被internalAdd引用的局部变量值val,再次以相同的参数执行委托,输出40。显然局部变量的改变影响到了委托的执行结果。

GetClosureFunction将internalAdd返回至外部,以30作为参数,去执行得到的结果是60,和val局部变量最后的值30是一致的。

val 作为一个局部变量。它的生命周期本应该在GetClosureFunction执行完毕后就结束了。为什么还会对之后的结果产生影响呢?

我们可以通过反编译来看下编译器为我们做的事情。

为了增加可读性,下面的代码对编译器生成的名字进行修改,并对代码进行了适当的整理。


class Program
{
    sealed class DisplayClass
    {
        public int val;

        public int AnonymousFunction(int x)
        {
            return x + this.val;
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(GetClosureFunction()(30));
    }

    static Func<int, int> GetClosureFunction()
    {
        DisplayClass displayClass = new DisplayClass();
        displayClass.val = 10;
        Func<int, int> internalAdd = displayClass.AnonymousFunction;

        Console.WriteLine(internalAdd(10));

        displayClass.val = 30;
        Console.WriteLine(internalAdd(10));

        return internalAdd;
    }
}

编译器创建了一个匿名类(如果不需要创建闭包,匿名函数只会是与GetClosureFunction生存在同一个类中,并且委托实例会被缓存,参见clr via C# 第四版362页),并在GetClosureFunction中创建了它实例。局部变量实际上是作为匿名类中的字段存在的。

4、 C#7对于不作为返回值的闭包的优化

如果在vs2017中编写第二节的代码。会得到一个提示,询问是否把lambda表达式(匿名函数)托转为本地函数。本地函数是c#7提供的一个新语法。那么使用本地函数实现闭包又会有什么区别呢?

如果还是第二节那样的代码,改成本地函数,查看IL代码。实际上不会发生任何变化。


class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GetClosureFunction()(30));
    }

    static Func<int, int> GetClosureFunction()
    {
        int val = 10;
        int InternalAdd(int x) => x + val;

        Console.WriteLine(InternalAdd(10));

        val = 30;
        Console.WriteLine(InternalAdd(10));

        return InternalAdd;
    }
}

但是当internalAdd不需要被返回时,结果就不一样了。

下面分别来看下匿名函数和本地函数创建不作为返回值的闭包的时候演示代码及经整理的反编译代码。

匿名函数


static void GetClosureFunction()
{
    int val = 10;
    Func<int, int> internalAdd = x => x + val;

    Console.WriteLine(internalAdd(10));

    val = 30;
    Console.WriteLine(internalAdd(10));
}

经整理的反编译代码


sealed class DisplayClass
{
    public int val;

    public int AnonymousFunction(int x)
    {
        return x + this.val;
    }
}

static void GetClosureFunction()
{
    DisplayClass displayClass = new DisplayClass();
    displayClass.val = 10;
    Func<int, int> internalAdd = displayClass.AnonymousFunction;

    Console.WriteLine(internalAdd(10));

    displayClass.val = 30;
    Console.WriteLine(internalAdd(10));
}

本地函数


class Program
{
    static void Main(string[] args)
    {
    }

    static void GetClosureFunction()
    {
        int val = 10;
        int InternalAdd(int x) => x + val;

        Console.WriteLine(InternalAdd(10));

        val = 30;
        Console.WriteLine(InternalAdd(10));
    }
}

经整理的反编译代码


// 变化点1:由原来的class改为了struct
struct DisplayClass
{
    public int val;

    public int AnonymousFunction(int x)
    {
        return x + this.val;
    }
}

static void GetClosureFunction()
{
    DisplayClass displayClass = new DisplayClass();
    displayClass.val = 10;

    // 变化点2:不再构建委托实例,直接调用值类型的实例方法
    Console.WriteLine(displayClass.AnonymousFunction(10));

    displayClass.val = 30;
    Console.WriteLine(displayClass.AnonymousFunction(10));
}

上述这两点变化在一定程度上能够带来性能的提升,目前的理解是,用结构体代替类,结构体实例能够在方法跑完后就立即释放,不需要等待垃圾回收,所以在官方的推荐中,如果委托的使用不是必要的,更推荐使用本地函数而非匿名函数。

到此这篇关于C#中闭包概念讲解的文章就介绍到这了,更多相关C# 闭包内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C#中闭包概念讲解

本文链接: https://www.lsjlt.com/news/130032.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#中闭包概念讲解
    理解C#中的闭包 1、 闭包的含义 首先闭包并不是针对某一特定语言的概念,而是一个通用的概念。除了在各个支持函数式编程的语言中,我们会接触到它。一些不支持函数式编程的语言中也能支持闭...
    99+
    2024-04-02
  • C++基础概念讲述
    目录1.C++相关网站推荐2.C++和C的关系3.C++特性说明3.1与底层硬件紧密结合3.2对象生命周期的精确控制3.3Zero-Overhead Abstraction首先,通过...
    99+
    2024-04-02
  • python中闭包的概念是什么
    闭包是指在一个函数内部定义的函数,并且内部函数可以访问外部函数的局部变量。具体来说,闭包是由函数对象和其引用环境组合而成的实体。 闭...
    99+
    2023-10-27
    python
  • golang闭包的概念是什么
    闭包是指一个函数值(函数的指针)与其引用的其环境变量(值)的组合,形成了一个整体。换句话说,闭包是一个包含自由变量(在函数中使用,但...
    99+
    2023-10-20
    golang
  • javascript闭包的概念和作用
    这篇文章主要讲解了“javascript闭包的概念和作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javascript闭包的概念和作用”吧!1 闭包--...
    99+
    2024-04-02
  • jquery闭包的概念是什么
    这篇文章主要讲解了“jquery闭包的概念是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“jquery闭包的概念是什么”吧! ...
    99+
    2024-04-02
  • Golang函数指针和闭包:概念解析
    摘要:1. 什么是函数指针?函数指针是存储函数地址的变量,允许将函数作为另一个函数的参数。2. 什么是闭包?闭包是对函数附加数据的函数,它捕捉到函数被调用时的作用域变量,使函数可以引用外...
    99+
    2024-04-15
    闭包 函数指针 golang 作用域
  • SpringBootCache缓存概念讲解
    目录Cache自动配置ImportSelectorGenericCacheConfigurationCacheManagerValidatorRedis CacheRedi...
    99+
    2022-12-30
    SpringBoot Cache SpringBoot Cache缓存
  • Javascript的独特的概念之闭包
    目录Javascript闭包简介:为什么是闭包:总结Javascript闭包简介: Javascript语言中,有一个独特的概念:闭包(closure),这在类似C++,Java等编...
    99+
    2024-04-02
  • c++分离讲解模板的概念与使用
    目录泛类编程函数模板函数模板的概念函数模板的使用函数模板的实例化函数模板的匹配原则类模板类模板的定义格式类模板的实例化泛类编程 学习模板,首先我们需要了解一下什么是泛类编程 #inc...
    99+
    2024-04-02
  • C语言哈希表概念超详细讲解
    目录1. 哈希概念2. 哈希冲突3. 哈希实现3.1 闭散列(哈希表)3.1.1 闭散列的细节3.1.2 优化后的闭散列3.2 扩散列(哈希桶)3.2.1 扩散列的细节4. 哈希表和...
    99+
    2023-02-09
    C语言哈希表 C语言哈希概念 C语言哈希实现
  • C++特殊类设计概念与示例讲解
    目录一、设计模式概念二、设计一个不能被拷贝的类三、设计一个只能在堆上创建对象的类3.1 私有构造3.2 私有析构四、设计一个只能在栈上创建对象的类五、设计不能被继承的类六、单例模式6...
    99+
    2023-05-17
    C++特殊类设计 C++设计模式
  • Java中StringUtils与CollectionUtils和ObjectUtil概念讲解
    目录一.解析概念StringUtils概念CollectionUtils概念ObjectUtil概念二.区别三.总结一.解析 概念 StringUtils概念 StringUtils...
    99+
    2022-12-27
    Java StringUtils Java CollectionUtils Java ObjectUtil
  • C#Marshal类基本概念和入门实例讲解
    目录C# Marshal类基本概念及入门C# Marshal.Copy实现非托管指针和数组之间的转换挑战写文件读文件总结C# Marshal类基本概念及入门 marshal:直译为...
    99+
    2023-02-26
    C# Marshal类 Marshal类基本概念 Marshal类入门
  • C++内存模型与名称空间概念讲解
    目录1、存储持续性与作用域及链接性2、作用域和链接3、静态持续变量4、静态持续性和外部链接性5、静态持续性与内部链接性6、静态存储性与无链接性7、const8、函数和链接性9、语言的...
    99+
    2023-01-02
    C++内存模型 C++名称空间
  • 一文搞懂JavaScript中最难理解概念之一的闭包
    目录一、闭包的概念二、怎么实现闭包三、闭包的用途1.封装私有变量2. 做缓存3. 模块化编程(实现共有变量)四、闭包的缺点五、最后的话一、闭包的概念 当通过调用外部函数返回的内部函数...
    99+
    2023-05-14
    JavaScript闭包实现 JavaScript闭包应用 JavaScript闭包
  • JavaScript中闭包的概念、原理及作用是什么
    本篇内容主要讲解“JavaScript中闭包的概念、原理及作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript中闭包的概念、原理及作用是...
    99+
    2024-04-02
  • C++详细分析讲解引用的概念与使用
    目录1.引用的概念2.引用的格式3.引用的特性4.取别名原则5.引用的使用场景做参数做返回值int&Count()的讲解传值传引用效率比较6.引用和指针的不同点1.引用的概念...
    99+
    2024-04-02
  • golang闭包的概念及作用是什么
    闭包是指一个函数(匿名函数或者lambda函数)以及其相关的引用环境组合而成的实体。在Go语言中,闭包是一种特殊的匿名函数,它可以访...
    99+
    2024-02-29
    golang
  • C++深入讲解类与封装的概念与使用
    目录一、类的组合二、类的封装三、类成员的作用域四、小结一、类的组合 电脑一般而言是由 CPU,内存,主板,键盘和硬盘等部件组合而成。 二、类的封装 类通常分为以下两个部分 类的实现...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作