C# for循环和带有闭包的foreach循环的不同行为
我无法解释我遇到的问题。基本上,如果在foreach循环中使用lambda语法,得到的答案与在for循环中使用lambda语法得到的答案不同。在下面的代码中,我在“dispatcher”类中注册了一个委托。然后,我在另一个委托中包装该委托,并返回这些包装委托的列表。然后我执行它们。执行包装函数列表的预期输出为1,2。然而,当我结合lambda和foreach循环时,我看不到这一点 这不是导致问题的代码,而是我可以用来重现它的最简单的例子。我不想讨论这个用例,我更想知道为什么会出现我不期望的行为。如果我使用下面的foreach循环和lambda语法,它将失败。如果我使用新的Action()语法和foreach,它就会工作,如果我在for循环中使用lambda语法,它就会工作。谁能解释一下这里发生了什么事。这让我很困惑C# for循环和带有闭包的foreach循环的不同行为,c#,lambda,C#,Lambda,我无法解释我遇到的问题。基本上,如果在foreach循环中使用lambda语法,得到的答案与在for循环中使用lambda语法得到的答案不同。在下面的代码中,我在“dispatcher”类中注册了一个委托。然后,我在另一个委托中包装该委托,并返回这些包装委托的列表。然后我执行它们。执行包装函数列表的预期输出为1,2。然而,当我结合lambda和foreach循环时,我看不到这一点 这不是导致问题的代码,而是我可以用来重现它的最简单的例子。我不想讨论这个用例,我更想知道为什么会出现我不期望的行为。
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));
}
}
公共类持有者
{
公共持有人(int ID,Dispatcher disp)
{
this.ID=ID;
显示寄存器(某物);
}
公共int ID{get;set;}
private void Something(int test){Console.WriteLine(ID.ToString());}
}
公共类调度器
{
列表m_Holder=新列表();
公共无效登记册(行动职能)
{
m_持有人添加(func);
}
公共列表ReturnWrappedList()
{
列表温度=新列表();
//对于(int i=0;i操作(p));
//}
foreach(m_持有人的var行为)
{
temp.Add(p=>action(p));//失败-给出2,2
//临时添加(新动作(动作));工作-给出1,2
}
返回温度;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var disp=new Dispatcher();
var hold1=新持有人(1,disp);
var hold2=新持有人(2,disp);
ForEach(p=>p(1));
}
}
您是否尝试过:
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
您是否尝试过:
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
这是捕获的闭包的经典问题,其作用域不是您所期望的。在foreach中,操作具有外部作用域,因此执行捕获循环的最后一个值。在for的例子中,您在内部作用域中创建操作,因此每次迭代时闭包都超过局部值。这是捕获闭包的经典问题,其作用域不是您所期望的。在foreach中,操作具有外部作用域,因此执行捕获循环的最后一个值。在for的例子中,您在内部作用域中创建操作,因此每次迭代时闭包都在局部值之上。这就是臭名昭著的“在循环变量之上闭包”问题
- (及)
- (及)
- 这就是臭名昭著的“关闭循环变量”问题