c# - 循环中的 Lambda 变量捕获 - 这里发生了什么?

标签 c# .net lambda

<分区>

我正在努力思考,这里发生了什么?编译器生成什么样的代码?

public static void vc()
{
    var listActions = new List<Action>();

    foreach (int i in Enumerable.Range(1, 10))
    {
        listActions.Add(() => Console.WriteLine(i));
    }

    foreach (Action action in listActions)
    {
        action();
    }
}

static void Main(string[] args)
{ 
  vc();
}

输出: 10 10 .. 10

根据 this ,每次迭代都会创建一个新的 ActionHelper 实例。所以在那种情况下,我认为它应该打印 1..10。 有人可以给我一些编译器在这里做什么的伪代码吗?

谢谢。

最佳答案

在这一行

 listActions.Add(() => Console.WriteLine(i));

变量 i 被捕获,或者如果您愿意,创建一个指向该变量内存位置的指针。这意味着每个 委托(delegate)都有一个指向该内存位置的指针。循环执行后:

foreach (int i in Enumerable.Range(1, 10))
{
    listActions.Add(() => Console.WriteLine(i));
}

由于明显的原因,i10,因此 Action(s) 中存在的所有指针所指向的内存内容变为 10。

换句话说,i 被捕获了。

顺便说一句,应该注意,根据 Eric Lippert 的说法,这种“奇怪”的行为将在 C# 5.0 中被解决

所以在 C# 5.0 中,您的程序将按预期打印:

1,2,3,4,5...10

编辑:

找不到 Eric Lippert 关于该主题的帖子,但这是另一篇:

Closure in a Loop Revisited

关于c# - 循环中的 Lambda 变量捕获 - 这里发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12861560/

相关文章:

c# - 如何从无参数构造函数调用带有 2 个参数的构造函数?

c# - 将消息从 Azure 服务总线队列发送到新的 asb 队列

c# - .NET 和带 DLLS 的配置文件

c# - EF Core FromSql 的可选参数

c# - 如何使用 SonarQube 的 C# 插件设置 FxCop 安装路径

c# - 来自 ASP.NET MVC 2 和 FormsAuthentication 的 Web 服务身份验证

.net - 自定义配置部分中是否可以包含任意 XML?

java - 将函数列表应用于 Java 流 .map() 方法

java - java 8 中的 Lambda 表达式(使用 java.util.Optional 在 HashMap 中进行空检查)

java - 如何在java中使用lambda表达式添加Map