for循环和带闭包的foreach循环的不同行为 [英] Different behaviors with a for loop and a foreach loop with closures

查看:129
本文介绍了for循环和带闭包的foreach循环的不同行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法解释遇到的一个问题.基本上,如果在foreach循环中使用lambda语法,则与在for循环中使用lambda语法相比,将得到不同的答案.在下面的代码中,我在"dispatcher"类中注册了一个委托.然后,我稍后将委托中的委托包装在另一个委托中,并返回这些包裹的委托的列表.然后执行它们.执行包装功能列表的预期输出为1,2.但是,当我结合使用lambda和foreach循环时,我看不到.

I can't explain an issue I've run across. Basically I get a different answer if I use lambda syntax in a foreach loop than if I use it in a for loop. In the code below I register a delegate in a "dispatcher" class. I then later wrap the delegate on the way out in another delegate and return a list of these wrapped delegates. I then execute them. The expected output of executing the wrapped function list is 1,2. However I don't see that when I combine a lambda and a foreach loop.

这不是导致此问题的代码,而是我可以重现的最简单的情况.我宁愿不讨论这种情况的用例,对于为什么会得到我不期望的行为,我感到更加好奇.如果我在lambda语法中使用下面的foreach循环,它将失败.如果我使用新的Action()语法和foreach,则可以使用,如果在for循环中使用lambda语法,则可以使用.谁能解释这是怎么回事.这真让我感到难过.

This is not the code that is causing the problem, but the simplest case I could make to reproduce it. I would prefer not to discuss use cases of this, I'm more curious as to why I get behavior I'm not expecting. If I use the foreach loop below with the lambda syntax it fails. If I use the new Action() syntax and a foreach it works, if I use the lambda syntax in a for loop it works. Can anyone explain what is going on here. This has me really stumped.

    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));
    }
}

推荐答案

这是臭名昭著的结束循环变量"的陷阱.

This is the infamous "closing over the loop variable" gotcha.

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆