C# 中的 lambda 如何绑定到 foreach 中的枚举器? [英] How does a lambda in C# bind to the enumerator in a foreach?

查看:16
本文介绍了C# 中的 lambda 如何绑定到 foreach 中的枚举器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚遇到了最意想不到的行为.我确信它以这种方式工作是有充分理由的.有人可以帮忙解释一下吗?

I just came across the most unexpected behavior. I'm sure there is a good reason it works this way. Can someone help explain this?

考虑这个代码:

var nums = new int[] { 1, 2, 3, 4 };
var actions = new List<Func<int>>();

foreach (var num in nums)
{
    actions.Add(() => num);
}

foreach (var num in nums)
{
    var x = num;
    actions.Add(() => x);
}

foreach (var action in actions)
{
    Debug.Write(action() + " ");
}

输出对我来说有点令人惊讶:

The output is a bit surprising for me:

4 4 4 4 1 2 3 4 

显然,lambda 引用枚举器的方式有问题.在foreach的第一个版本中,'num'实际上绑定到'Current',而不是它返回的结果?

Obviously there's something going on with how the lambda is referencing the enumerator. In the first version of the foreach, is 'num' actually bound to 'Current', instead of the result returned by it?

推荐答案

这是关于 lambda 的众所周知的既定行为,尽管经常让那些第一次遇到它的人感到惊讶.根本问题是您对 lambda 是什么的心理模型并不完全正确.

This is well-known and established behavior regarding lambdas, though frequently surprising to those who've encountered it for the first time. The fundamental issue is that your mental model of what a lambda is isn't quite correct.

一个 lambda 是一个在被调用之前不会运行的函数.您的闭包绑定了对该 lambda 实例的引用,而不是值.当您在最终的 foreach 循环中执行您的操作时,这是您第一次实际跟踪封闭引用以查看它是什么.

A lambda is a function that doesn't get run until it's invoked. Your closure binds a reference to that lambda instance, not the value. When you execute your actions in your final foreach loop, that's the first time you're actually following the closed reference to see what it is.

在第一种情况下,您引用的是 num,此时 num 的值为 4,所以当然所有输出都是 4.在第二种情况下,每个 lambda 都绑定到不同的值每次都是循环本地的,并且该值没有改变(它没有被 GC 仅仅因为 lambda 引用.)因此,你得到了你期望的答案.

In the first case, you're referencing num, and at that point, the value of num is 4, so of course all your output is 4. In the second case, each lambda has been bound to a different value that was local to the loop each time, and that value isn't changed (it hasn't been GC'd solely because of the lambda reference.) therefore, you get the answer that you expect.

对局部临时值的闭包实际上是从 lambda 中的某个时间点捕获特定值的标准方法.

The closure over a local temporary value is actually the standard approach to capture a specific value from a point in time within the lambda.

亚当的 指向 Eric Lippert 博客的链接 提供了对正在发生的事情的更深入(且技术上准确)的描述.

Adam's link to Eric Lippert's blog provides a more in-depth (and technically accurate) description of what's going on.

这篇关于C# 中的 lambda 如何绑定到 foreach 中的枚举器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆