一个需要注意的地方
看下面的代码:

using System;
using System.Collections.Generic;
using System.Linq; namespace MyCsStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Func<int>> list = new List<Func<int>>();             for (int i = 0; i < 3; i++)
            {
                list.Add(() => i); //list依次添加0,1,2??
            }
            foreach (var item in list)
            {
                Console.WriteLine(item()); //输出的竟然是?
            }
        }
    }
}

运行试一下看看结果,如果你以前碰到过js里的闭包问题,相信你不会大惊小怪(而且可能已经知道了问题的原因),但是,如果你从来没有碰到过这种情况,是不是令你大吃一惊?!输出的竟然不是0,1,2,而是三个3,oh,my god。紧接着,立刻,你会大胆想到这里的list在Add方法执行的地方Add进去的是一个引用类型(这里是lambda表达式()=>i),它们执行的结果共同指向值为3的同一个引用地址!
没错,我们详细分析一下:
1、我们首先定义一个list,其存储格式为func<int>,即返回int型的代理;然后,用for循环将i封装进lambda表达式,并加入到该list中,最后,用foreach循环输出结果。
2、因为lambda表达式实质就是个委托,也就指向一个匿名函数,所以,在foreach输出的时候,使用item()来调用它,让它所指向的函数执行。
至于第2步中item()执行的结果为什么都是3,原因是这样的:
(1)在for循环中,只能有一个 i 变量。即在第一次循环时,i 的地址就分配好了(注意了,这里i的地址第一次分配后是不变的),不会因为循环次数的多少而发生任何改变,其改变的只能是里面装载的值。
(2)lambda表达式在构造时, 传进去的是变量的地址,而不是具体值。只有当真正执行这个lambda表达式时,才会去确定它的值。这就是为什么上面的例子中,其结果均为3(for循环在最后,当i=2时,i又加了1)。

那么如何解决这个问题?解决方案很简单:

1是在for循环中,定义一临时变量tmpNum,存储i的值即可。因为编译器会对该临时变量重新分配内存,这样,每次循环,都重新分配新的内存,就不会有这个问题了。

2用foreach也是同样的道理

Lambda表达式和For循环使用需要注意的一个地方的更多相关文章

  1. 在Lambda表达式中使用循环变量

    在C#5.0之前,如果在foreach循环中的lambda表达式里使用循环变量,那么你会发现一些意想不到的现象,例子如下: , , , }; var actions = new List<Act ...

  2. 用lambda表达式替代 for循环进行批量操作。

    IEnumerable<Rect> rectlist3 = rectlist.Select(rect =>newRect(rect.X + 2000, rect.Y, rect.re ...

  3. entity framework 新手入门篇(1.5)-lambda表达式与linq

    在建立好了EF模型之后,先不着急使用它,在使用它之前,你还需要了解两个相关的技术,lambda表达式与linq. 作为微软C#语言中重要的语法糖-lambda表达式与LINQ,本质都是一个方法,以la ...

  4. Java语言与JVM中的Lambda表达式全解

    Lambda表达式是自Java SE 5引入泛型以来最重大的Java语言新特性,本文是2012年度最后一期Java Magazine中的一篇文章,它介绍了Lamdba的设计初衷,应用场景与基本语法. ...

  5. 掌握 Java 8 Lambda 表达式

    Lambda 表达式 是 Java8 中最重要的功能之一.使用 Lambda 表达式 可以替代只有一个函数的接口实现,告别匿名内部类,代码看起来更简洁易懂.Lambda 表达式 同时还提升了对 集合 ...

  6. Java中Lambda表达式的使用

    简介(译者注:虽然看着很先进,其实Lambda表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能.本人建议不要乱用,因 ...

  7. Java Lambda表达式入门[转]

    原文链接: Start Using Java Lambda Expressions http://blog.csdn.net/renfufei/article/details/24600507 下载示 ...

  8. JDK8的新特性——Lambda表达式

    JDK8已经发布快4年的时间了,现在来谈它的新特性显得略微的有点“不合时宜”.尽管JDK8已不再“新”,但它的重要特性之一——Lambda表达式依然是不被大部分开发者所熟练运用,甚至不被开发者所熟知. ...

  9. Java函数式编程和lambda表达式

    为什么要使用函数式编程 函数式编程更多时候是一种编程的思维方式,是种方法论.函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做.说白了,函数式编程是基于 ...

随机推荐

  1. java 对CSV 文件的读取与生成

    CSV文件是以逗号分隔值的文件格式,一般用WORDPAD或记事本(NOTE),EXCEL打开.CSV(逗号分隔值)是一种用来存储数据的纯文本文件,通常都是用于存放电子表格或数据的一种文件格式,对于CS ...

  2. 十九、curator recipes之PathChildrenCache

    简介 curator可以监听路径下子节点的变更操作,如创建节点,删除节点 官方文档:http://curator.apache.org/curator-recipes/path-cache.html ...

  3. javaSE——字节流

    IO流:InputStream/OutputStream 字节流:         文件输出流 :内存 ——>文件 文件输入流 :内存<——文件 应用             文件输入/出 ...

  4. Jquery插件网站持续添加。。。

    Look Fro Less,Do More www.jq22.com

  5. ubuntu禁止系统自动升级之界面操作

    ##第一步:首先找到System Settings,如下图所示: ##第二步:然后找到Solfware & Updates,如下图所示: ##第三步:点击Solfwate & Upda ...

  6. 深入解析 ERP 计划的各个层次

    ERP 生产计划管理按照 ERP 计划的层次主要分为:经营规划.销售和运作规划.主生产计划.物料需求计划.能力需求计划.执行能力计划.执行物料计划等. 经营规划是企业的战略规划,用于确定企业经营目标和 ...

  7. node(3)MVC代码结构模式moogoDB的学习

    ---恢复内容开始--- 一.MVC代码结构模式 设计模式:观察者模式.中介者模式,这种模式,主要做的事情是处理类与类之间‘高内聚.低耦合’; 代码架构模式:MVC.MVVM.MVP Model:模型 ...

  8. .hiverc

    使用hive cli的时候,会读取.hiverc脚本,在.hiverc脚本里可以做一些自己的预设. 比如: set hive.cli.print.current.db=true; set hive.c ...

  9. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)

    相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...

  10. Python 应用剖析工具介绍

    [编者按]本文作者为来自 HumanGeo 的工程师 Davis,主要介绍了用于 Python 应用性能分析的几个工具.由国内 ITOM 管理平台 OneAPM 编译呈现. 在 HumanGeo,我们 ...