for循环和带闭包的foreach循环的不同行为

我无法解释我遇到的问题。 基本上,如果我在foreach循环中使用lambda语法,那么我会得到一个不同的答案,而不是在for循环中使用它。 在下面的代码中,我在“调度程序”类中注册一个委托。 然后我在另一个委托中将委托包装出来并返回这些包装委托的列表。 然后我执行它们。 执行包装函数列表的预期输出为1,2。 但是当我组合lambda和foreach循环时,我没有看到。

这不是引起问题的代码,而是我可以用来重现它的最简单的情况。 我不想讨论这个用例,我更好奇为什么我得到的行为我没想到。 如果我使用lambda语法使用下面的foreach循环,它将失败。 如果我使用新的Action()语法和foreach它可以工作,如果我在for循环中使用lambda语法,它就可以工作。 任何人都可以解释这里发生了什么。 这让我很难过。

public class Holder { public Holder(int ID, Dispatcher disp) { this.ID = ID; disp.Register(Something); } public int ID { get; set; } private void Something(int test) { Console.WriteLine(ID.ToString()); } } public class Dispatcher { List<Action> m_Holder = new List<Action>(); public void Register(Action func) { m_Holder.Add(func); } public List<Action> ReturnWrappedList() { List<Action> temp = new List<Action>(); //for (int i = 0; i  action(p)); //} foreach (var action in m_Holder) { temp.Add(p => action(p)); //Fails - gives 2,2 //temp.Add(new Action(action)); Works - gives 1,2 } return temp; } } class Program { static void Main(string[] args) { var disp = new Dispatcher(); var hold1 = new Holder(1, disp); var hold2 = new Holder(2, disp); disp.ReturnWrappedList().ForEach(p => p(1)); } } 

这是臭名昭着的“关闭循环变量”陷阱。

  • 关闭循环变量被认为是有害的 (和第二部分 )

你有没有尝试过:

 foreach (var action in m_Holder) { var a = action; temp.Add(p => a(p)); } 

这是捕获闭包的经典问题,其范围不是您所期望的。 在foreach中,action具有外部作用域,因此执行捕获循环的最后一个值。 在for case中,您在内部作用域中创建操作,因此闭包在每次迭代时都超过了本地值。