防止Lambda的各种坑爹(二)

防止Lambda的各种坑爹(二)

  2.循环内的被捕获的变量。

  首先看一段代码:

防止Lambda的各种坑爹(二)
防止Lambda的各种坑爹(二)
View Code

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Lambda2
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13             List<Action> list = new List<Action>();
14             for (int i = 0; i < 3; i++)
15             {
16                 int current = i;
17                 list.Add(() =>
18                 {
19                     Console.Write(current);
20                     current++;
21                 });
22             }
23 
24             foreach (var item in list)
25             {
26                 item();
27             }
28             list.First()();
29             list.First()();
30 
31             Console.Read();
32         }
33     }
34 }

  你能猜出输出的是什么吗?如果你的答案是01212,那么恭喜你,你的答案是正确的。这里可以看出:当在Lambda中捕获一个变量时,被捕获的是变量的实例。也就是说,循环第一次捕获的变量将有别与循环第二次捕获的变量,就像有3个current变量一样,全部叫做current,他们一个接一个的创建。

  代码会创建3个不同的委托—每次循环都会创建一个,添加到一个List集合中。现在,由于current变量是在循环内声明的,所以每次循环迭代。他都会被创建。这样每次委托捕获到的都是不同的current变量的值。所以一次调用每个委托。输出的结果依次是0 1 2。然后我们在执行2个第一个委托,由于在执行了current++,所以依次再输出 1 2。

  我想你一定不奇怪为什么每次的current变量的值不同,因为这个看上次似乎是理所当然的。是这样吗?我们通过ILDASM查看对应生成的IL代码:发现编译器依旧为我们生成的了一个类DisPlayClass1,这个类包装了current变量和委托包装的方法 <Main>b__0:void: Console.Write(current);current++。

防止Lambda的各种坑爹(二)

  同时可以看到new DisplayClass1的位置在循环内部

防止Lambda的各种坑爹(二)

  对应的C#代码我想是这样的

防止Lambda的各种坑爹(二)
防止Lambda的各种坑爹(二)
View Code

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Lambda2
 8 {
 9     class Program
10     {
11         private class DisplayClass1
12         {
13             public int current;
14 
15             public void F()
16             {
17                 Console.Write(current);
18                 current++;
19             }
20         }
21 
22         static void Main(string[] args)
23         {
24 
25             List<Action> list = new List<Action>();
26             for (int i = 0; i < 3; i++)
27             {
28                 DisplayClass1 d = new DisplayClass1();
29                 d.current = i;
30                 list.Add(d.F);
31             }
32 
33             foreach (var item in list)
34             {
35                 item();
36             }
37             list.First()();
38             list.First()();
39 
40             Console.Read();
41         }
42     }
43 }

  好了,这样的话就有了一个新问题,应该思考的一点是,如果我们移除current变量,直接用for循环中的i的代替的话,那么会发生什么呢?在这种情况下,所以的循环内的委托共享的是一个变量i。输出的将是3 4 5 6 7。之所以这样,是因为在循环结束时,i的值是3(同时要注意的是,委托内的i++不会现在执行)。之后的每次调用委托都会使i++,每个委托都是调用的同一个变量i。如下代码将证实这一点:

防止Lambda的各种坑爹(二)
防止Lambda的各种坑爹(二)
View Code

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Lambda2
 8 {
 9     class Program
10     {
11         static void Main(string[] args)
12         {
13 
14             List<Action> list = new List<Action>();
15             for (int i = 0; i < 3; i++)
16             {
17                 list.Add(() =>
18                 {
19                     Console.Write(i);
20                     i++;
21                 });
22             }
23 
24             foreach (var item in list)
25             {
26                 item();
27             }
28             list.First()();
29             list.First()();
30 
31             Console.Read();
32         }
33     }
34 }

  同时看到对应的IL代码,new DisplayClass1的位置在循环外部

防止Lambda的各种坑爹(二)

  好了,这个提醒我们以后在循环内部使用Lambda表达式的时候需要注意的地方。

转载于:https://www.cnblogs.com/LoveJerryZhang/archive/2012/12/04/2800651.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110270.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • LaTeX 插入图片 公式

    LaTeX 插入图片 公式一、LaTeX插入图片首先需要添加一个宏包graphicx,在插入图片的位置可以直接点击LaTeX的插入图片快捷按钮,然后修改其中的*位置的内容既可(caption与label若不需要也可以删掉)。\documentclass{article}\usepackage{graphicx}\begin{document}\begin{figure}\centering…

    2022年5月1日
    48
  • SpringMVC+easyUI CRUD 添加数据C

    SpringMVC+easyUI CRUD 添加数据C

    2022年1月30日
    34
  • Windows Server AppFabric安装与步署[通俗易懂]

    Windows Server AppFabric安装与步署[通俗易懂]WindowsServerAppFabric正式版已经发布。今天测试一下,把域环境中安装遇到的问题告诉大家,只针对缓存服务这一块,希望大家少走一些弯路。1、首先下载安装WindowsServerAppFabric,地址:http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=467e5…

    2022年10月11日
    0
  • 【OpenGrok代码搜索引擎】一、OpenGrok简介

    【OpenGrok代码搜索引擎】一、OpenGrok简介OpenGrok是一个快速的、非常有用的代码搜索和交叉引用引擎。它由Java语言编写而成。它可以帮助你快速的搜索,交叉引用和索引你的代码树。它可以很好的识别多种应用程序文件格式和代码版本控制工具。

    2022年4月30日
    43
  • 版权文字:Power by DedeCms 如何去除?[通俗易懂]

    版权文字:Power by DedeCms 如何去除?[通俗易懂]dedeCMS系统中的版权声明信息中含有“PowerbyDedeCms”字样,如何去除?dedeCMS近期的新版本至2013-6-7更新包以来,不管新版还是旧版更新补丁包,更新后网站页底都会出现powerbydedecms。*一、powerbydedecms什么意思?在我们上网的时候,会见到页面页底很多带powerbydedecms的网站,powerbydede…

    2022年7月13日
    16
  • 数据库二级映射是什么_内存映射技术

    数据库二级映射是什么_内存映射技术1.     概述LMDBiscompact(紧凑的),fast,powerful,androbustandimplementsasimplifiedvariantoftheBerkeleyDB(BDB)API.(BDBisalsoverypowerful,andverboselydocumentedinitsownright.)Afterre…

    2022年9月28日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号