闭包

概念

闭包是指捕获(引用)了作用域外的函数的局部变量的函数。

由于外部函数的局部变量被捕获,即使外层函数执行已终止,内部定义的函数也可以访问外部函数的局部变量,所以局部变量的生命周期得到了延长。

闭包本质是一个对象(编译后) 。

当定义一个闭包时,编译器会生成一个类,这个类的实例就是闭包对象,这个类包含了闭包所引用的外部变量和代码块。当调用闭包时,实际上是在调用这个类的实例。

在C#中我们可以使用委托和Lambda表达式来实现闭包。

案例

public class Test
{
    public Action action;
    static void Main(string[] args)
    {
        F1();
        action();
    }
    //外部函数F1
    public void F1()
    {
        //定义局部变量a
        int a = 1;
 
        //内部定义嵌套函数F2
        void F2()
        {
            a += 1;
            Console.WriteLine(a);
        }
        //订阅函数F2
        action += F2;
 
        //内部定义嵌套函数F3
        void F3()
        {
            a += 1;
            Console.WriteLine(a);
        }
        //订阅函数F3
        action += F3;
 
        //订阅Lambda表达式匿名函数
        action += () =>
        {
            a += 0;
            Console.WriteLine(a);
        };
    }
}

执行结果为 2,3,3;

过程解析:

内部定义的函数F2,函数F3,匿名函数都捕获了外部函数F1的局部变量a,并将三个方法依次订阅action委托并调用。

由于三个内部定义函数都是直接引用a,所以捕获的是a的内存地址,修改会影响到a本身。

即使外层函数F1执行已终止,内部定义的三个函数也可以访问外层函数F1的局部变量a,所以局部变量a的生命周期得到了延长。

第一个结果为函数F2执行的a += 1;此时a为1 + 1 = 2

第二个结果为函数F3执行的a += 1;此时a为2 + 1 = 3

第三个结果为匿名函数执行的a += 0;此时a为3 + 0 = 3

用途

  • 用于创建私有变量,限制外部对变量的直接访问和修改,提高代码的封装性;
  • 用来模拟私有方法,将数据隐藏和封装;
  • 可以重复使用变量,并且不会造成变量污染;
  • 实现回调函数时常常会使用闭包,将函数和相关的数据引用打包在一起,方便在特定事件发生时调用;

隐患

内存泄露

变量长期驻扎在内存中,可能导致内存泄漏。如果闭包不再需要,可以手动释放,比如将闭包设置为null,以便让垃圾回收器回收。

闭包陷阱

Action<int> actions = new Action<int>();
for (int i = 0; i < 5; i++)
{
    actions += (() =>
    {
        Console.WriteLine(i)
    });
}
foreach (int i in actions)
{
    Console.WriteLine(i);
}

首先创建了一个委托,然后for循环里的5个匿名函数都捕获了循环变量i,因此形成了闭包。

当执行这个程序时,期望输出的是数字1到5,但实际上输出的是数字5,5,5,5,5。这是因为每个匿名函数都引用了同一个变量i的内存地址,而这个变量的值在循环结束后变成了5。所以当我们调用这些匿名函数时,它们都输出变量i的最终值5。

为了避免这个陷阱,我们可以在每次循环时定义一个新的局部变量j,将循环变量i的值复制到局部变量j中,然后让匿名函数捕获(引用)局部变量j。这样,每个匿名函数都引用的是新定义的不同的变量j,而不同一个循环变量i。修改后的代码:

Action<int> actions = new Action<int>();
for (int i = 0; i < 5; i++)
{
    //局部变量j
    int j = i;
    //Lambda简写,省略了花括号
    actions+=(() => Console.WriteLine(j));
}
foreach (int i in actions)
{
    Console.WriteLine(i);
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇