C# 闭包有效吗? [复制]
Posted
技术标签:
【中文标题】C# 闭包有效吗? [复制]【英文标题】:C# Closure works? [duplicate] 【发布时间】:2012-04-10 01:30:25 【问题描述】:可能重复:Is there a reason for C#'s reuse of the variable in a foreach?Looping through a list of Actions
今天我遇到了一个关于 C# foreach 函数的问题,它没有给我预期的正确结果。这是代码:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
class Program
static void Main(string[] args)
int[] data = new int[] 1, 2, 3, 4, 5 ;
List<Func<int>> actions = new List<Func<int>>();
foreach (int x in data)
actions.Add(delegate() return x; );
foreach (var foo in actions)
Console.WriteLine(foo());
Console.ReadKey();
当我在控制台应用程序中运行它时,它在屏幕上打印了五个 5。为什么?我只是无法理解。问了一些人,他们只是说这段代码中有闭包,但是我不是很清楚,我记得在javascript中我经常遇到闭包,但是在上面的代码中,为什么会有闭包?谢谢。
【问题讨论】:
看看:***.com/questions/9569334/… blogs.msdn.com/b/ericlippert/archive/2009/11/12/… 这个问题几乎每天都会被问到。请参阅***.com/questions/8898925/… 以获得对该问题的良好讨论。 【参考方案1】:在 C#4 中,foreach
循环的所有迭代共享相同的变量,因此也共享相同的闭包。
规范说:
foreach (V v in x) embedded-statement
然后扩展为:
E e = ((C)(x)).GetEnumerator(); try V v; while (e.MoveNext()) v = (V)(T)e.Current; embedded-statement finally … // Dispose e
您可以看到v
是在while
-loop 之外的块中声明的,这导致了这种共享行为。
这可能会在 C#5 中改变。
我们正在进行重大更改。在 C# 5 中,foreach 的循环变量在逻辑上将位于循环内部,因此闭包每次都会关闭变量的新副本。 “for”循环不会改变。
http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
【讨论】:
为什么这个早期的规范说 v 在 while 循环中声明 msdn.microsoft.com/en-GB/library/aa664754.aspx【参考方案2】:关键是,当您在 foreach
循环中创建委托时,您正在为循环创建一个闭包变量 x
,不是它的当前值 .
只有当你执行actions
中的委托时才会确定值,也就是x
当时的值。由于您已经完成了 foreach
循环,因此该值将是您的 data
数组中的最后一项,即 5。
【讨论】:
+1:非常清晰简洁的解释。 请务必注意,最后一句仅适用于 C#4 及更早版本。 ..正如你已经指出的那样,所以我不想重复它;-)以上是关于C# 闭包有效吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
我可以使用原型模式而不是闭包模式来创建解析为对象的承诺吗? [复制]