[C#学习笔记] - C#中闭包的一些理解

持续更新中…

引言

看过一些文章,总结下来就是,闭包是一个带共享数据的函数。内层的函数(子函数)可以引用包含在它外层函数(父函数)的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时的值,而是在父函数范围内的最终值。嵌套定义函数,使用了外部定义域(父函数定义域)(非全局定义域)的变量。是否有返回值并不影响判断。

javascript的闭包理解:函数可以使用函数之外定义的变量。

示例

这三个函数几乎一样,唯一不同的就是action函数里变量。
函数action => Console.WriteLine(x)关联的变量是x。这个匿名函数以该形式保存。直至被调用时,才会去取对应的i


private static void F1()
{
    IList<Action> actions = new List<Action>();
    for (int i = 0; i < 5; i++)
    {
        actions.Add(() => Console.WriteLine(i));
    }
    foreach (var action in actions)
    {
        action();
    }
}
ouput:5 5 5 5 5

这个例子比较容易理解。循环结束后,i=5。所以去遍历actions时,所有的action => Console.WriteLine(x)使用的是变量i,因此结果是 5 5 5 5 5。


private static void F2()
{
    IList<Action> actions = new List<Action>();
    for (int i = 0; i < 5; i++)
    {
        int j = i;
        actions.Add(() => Console.WriteLine(j));
    }
    foreach (var action in actions)
    {
        action();
    }
}
ouput:0 1 2 3 4

这里j是循环里的局部变量,并不受i++的影响。action => Console.WriteLine(x)使用的是变量j,在每次循环后就已经固定下来。因此结果是 0 1 2 3 4。


private static void F3()
{
    int j;
    IList<Action> actions = new List<Action>();
    for (int i = 0; i < 5; i++)
    {
        j = i;
        actions.Add(() => Console.WriteLine(j));
    }
    foreach (var action in actions)
    {
        action();
    }
}
ouput:4 4 4 4 4

这个的思路与F1类似。只是因为循环结束后,i=5j=4。因此结果是 4 4 4 4 4。但与F2做比较,就能发现他们的重大区别,很有参考意义。

应用

上面的例子只是一种很标准的闭包格式。其实很多时候我们在使用lambda表达式时候,已经属于闭包范围了。如有一个list数据,我们希望通过多线程,每个线程处理其中的一个对象。于是有如下正确与错误的示例。

List<UserModel> userList = new List<UserModel>
{
    new UserModel{ UserName="A", UserAge = 1},
    new UserModel{ UserName="B", UserAge = 2},
    new UserModel{ UserName="C", UserAge = 3}
};

// 错误
for (int i = 0; i < 3; i++)
{
    ThreadPool.QueueUserWorkItem((obj) =>
    {
        Thread.Sleep(100);
        UserModel u = userList[i];// i永远都是userList.Count
        Console.WriteLine("case1:\t" + u.UserName);
        // 等价于
        // Console.WriteLine("case1:\t" + userList[i].UserName);
    });
}

// 正确
for (int i = 0; i < 3; i++)
{
    UserModel u = userList[i];
    ThreadPool.QueueUserWorkItem((obj) =>
    {
        Thread.Sleep(100);
        Console.WriteLine("case2:\t" + u.UserName);
    });
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值