我无法解释我遇到的问题。基本上,如果我在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<int>> m_Holder = new List<Action<int>>();
public void Register(Action<int> func)
{
m_Holder.Add(func);
}
public List<Action<int>> ReturnWrappedList()
{
List<Action<int>> temp = new List<Action<int>>();
//for (int i = 0; i < m_Holder.Count; i++) //Works - gives 1, 2
//{
// var action = m_Holder[i];
// temp.Add(p => action(p));
//}
foreach (var action in m_Holder)
{
temp.Add(p => action(p)); //Fails - gives 2,2
//temp.Add(new Action<int>(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));
}
}
答案 0 :(得分:4)
这是臭名昭着的“关闭循环变量”问题。
答案 1 :(得分:0)
你试过了吗?
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
答案 2 :(得分:0)
这是捕获闭包的经典问题,其范围与您的预期不符。在foreach中,action具有外部作用域,因此执行会捕获循环的 last 值。在for case中,您在内部作用域中创建动作,因此闭包在每次迭代时都超过了本地值。