C# 闭包

作者: 周末的游戏之旅 | 来源:发表于2019-08-13 09:28 被阅读0次

闭包的概念

内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。

闭包的优点

使用闭包,我们可以轻松的访问外层函数定义的变量,例如在匿名方法中。比如有如下场景,在WinForm中,我们希望当用户关闭窗体时,给用户一个提示。代码如下:

private void Form1_Load(object sender, EventArgs e)
{
       string tipWords = "您将关闭当前对话框";
       this.FormClosing += delegate
       {
            MessageBox.Show(tipWords);
       };
}

若不使用匿名方法,我们就需要使用其他方式将tipWords变量的值传递给FormClosing注册的处理函数,这就增加了不必要的工作量。

闭包陷阱

例如有如下代码:

private static void Before()
{
    Action[] actions = new Action[10];

    for (var i = 0; i < actions.Length; i++)
    {
        actions[i] = () =>
        {
            Console.WriteLine(i);
        };
    }

    foreach (var item in actions)
    {
        item();
    }
}

输出结果


闭包陷阱解释:

  1. 在for循环中,只能有一个 i 变量。即在第一次循环时,i 的地址就分配好了(注意了,这里i的地址第一次分配后是不变的),不会因为循环次数的多少而发生任何改变,其改变的只能是里面装载的值。
  2. 当使用匿名方法时传进去的是变量的地址,而不是具体值。只有当真正执行这个匿名方法时,才会去确定它的值。这就是为什么上面的例子中,其结果均为10(for循环在最后,当i=9时,i又加了1)。

编译器帮我们做了什么

下面的代码是编译器帮我们生成的代码

private static void After()
{
    Action[] actions = new Action[10];

    var anonymous = new AnonymousClass();

    for (anonymous.i = 0; anonymous.i < actions.Length; anonymous.i++)
    {
        actions[anonymous.i ] = anonymous.Action;
    }

    foreach (var item in actions)
    {
        item();
    }
}

class AnonymousClass
{
    public int i;

    public void Action()
    {
        Console.WriteLine(this.i);
    }
}

如何避免闭包陷阱

  1. 就是在for循环中,定义一临时变量tmpNum,存储i的值即可。因为编译器会对该临时变量重新分配内存,这样,每次循环,都重新分配新的内存,就不会有这个问题了。
  2. 使用foreach,c#5.0后,for和foreach在处理闭包问题上有了一些新的改变。为了适应不同的需求,微软对佛 foreach做了调整,“foreach”的遍历中定义的临时循环变量会被逻辑上限制在循环内,“foreach”的每次循环都会是循环变量的一个拷贝,这样闭包就看起来关闭了(没有了)。

相关文章

  • C# 闭包

    闭包的概念 内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时...

  • C#闭包陷阱

    在C#中,lambda(匿名委托)使用时,编译器会自动生成一个类来保存lambda中的方法以及字段,当lambda...

  • swift-闭包

    闭包 闭包定义 闭包简化 - 尾随闭包 闭包参数 闭包返回值 闭包的循环引用

  • 闭包,闭包,闭包

    1、这家伙到底是什么? 网上关于这个的讨论的太多了太多了,有各种的举例子,但是大部分还在寻找这个答案的小伙伴对于变...

  • 闭包-Closures [swift 5.1]

    闭包的语法 尾随闭包 闭包逃离 自动闭包

  • Day7 闭包(Closures)

    本页包含内容:• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包 1、闭包表达式 闭包...

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • 闭包(closure)

    ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...

  • swift- 闭包一

    /*• 闭包表达式• 尾随闭包• 值捕获• 闭包是引用类型• 逃逸闭包• 自动闭包*/

  • (9) python之闭包

    闭包闭包 = 函数 + 环境变量(函数定义的时候) 一个最简单的闭包 闭包不受外部变量影响 非闭包 闭包 闭包 只...

网友评论

      本文标题:C# 闭包

      本文链接:https://www.haomeiwen.com/subject/btamjctx.html