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

C# for循环和带有闭包的foreach循环的不同行为,c#,lambda,C#,Lambda,我无法解释我遇到的问题。基本上,如果在foreach循环中使用lambda语法,得到的答案与在for循环中使用lambda语法得到的答案不同。在下面的代码中,我在“dispatcher”类中注册了一个委托。然后,我在另一个委托中包装该委托,并返回这些包装委托的列表。然后我执行它们。执行包装函数列表的预期输出为1,2。然而,当我结合lambda和foreach循环时,我看不到这一点 这不是导致问题的代码,而是我可以用来重现它的最简单的例子。我不想讨论这个用例,我更想知道为什么会出现我不期望的行为。

我无法解释我遇到的问题。基本上,如果在foreach循环中使用lambda语法,得到的答案与在for循环中使用lambda语法得到的答案不同。在下面的代码中,我在“dispatcher”类中注册了一个委托。然后,我在另一个委托中包装该委托,并返回这些包装委托的列表。然后我执行它们。执行包装函数列表的预期输出为1,2。然而,当我结合lambda和foreach循环时,我看不到这一点

这不是导致问题的代码,而是我可以用来重现它的最简单的例子。我不想讨论这个用例,我更想知道为什么会出现我不期望的行为。如果我使用下面的foreach循环和lambda语法,它将失败。如果我使用新的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));
    }
}
公共类持有者
{
公共持有人(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的例子中,您在内部作用域中创建操作,因此每次迭代时闭包都在局部值之上。

这就是臭名昭著的“在循环变量之上闭包”问题

  • (及)
    • 这就是臭名昭著的“关闭循环变量”问题

      • (及)

      谢谢,我认为这与编译器如何执行foreach循环有关,但我无法准确地找出问题所在。谢谢,我认为这与编译器如何执行foreach循环有关,但我无法准确地找出问题所在