sco*_*obi 13 c# foreach lambda
我刚刚遇到了最意想不到的行为.我确信这有一个很好的理由.有人可以帮忙解释一下吗?
考虑以下代码:
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() + " ");
}
Run Code Online (Sandbox Code Playgroud)
输出对我来说有点意外:
4 4 4 4 1 2 3 4
Run Code Online (Sandbox Code Playgroud)
显然,lambda是如何引用枚举器的.在foreach的第一个版本中,'num'实际上是绑定到'Current',而不是它返回的结果?
这是关于lambdas的众所周知和已确立的行为,尽管对于那些第一次遇到它的人来说经常是令人惊讶的.最根本的问题是,你的拉姆达什么心理模型是不完全正确的.
lambda是一个在调用之前不会运行的函数.你的闭包绑定了对该lambda实例的引用,而不是值.当您在最终的foreach循环中执行操作时,这是您第一次实际关注已关闭的引用以查看它是什么.
在第一种情况下,您正在引用num,并且此时num的值为4,因此当然所有输出都是4.在第二种情况下,每个lambda已绑定到本地的不同值每次循环,并且该值不会更改(它仅仅因为lambda引用而没有GC.)因此,您得到了您期望的答案.
对本地临时值的闭包实际上是从lambda中的某个时间点捕获特定值的标准方法.
Adam 与Eric Lippert博客的链接提供了更深入(技术上准确)的描述.
| 归档时间: |
|
| 查看次数: |
1829 次 |
| 最近记录: |