事件匿名函数参数无法正常工作

时间:2011-09-25 18:26:10

标签: c#

PictureBox[,] picBoard = new PictureBox[3, 3];

for(int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
    {
        picBoard[i, j] = new PictureBox();
        picBoard[i, j].Click += new EventHandler(
          (sender, e) => Debug.WriteLine(i.ToString() + " " + j.ToString()));
    }

我试图让picBoard [i,j]在点击时打印它在2D数组中的位置。问题是每个PictureBox在单击时打印“3 3”。这对我没有任何意义,因为我和j永远不会等于3.我尝试在Debug.Writeline()中用500替换i,并且它按预期执行(总是打印“500 3”)。

3 个答案:

答案 0 :(得分:1)

它们被匿名方法捕获,一旦你离开循环,它们的值就是3.当回调实际执行时,它们的值是3.要修复代码,你需要关闭局部变量:

PictureBox[,] picBoard = new PictureBox[3, 3];
for(int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
    var x = i;
    var y = j;
    picBoard[i, j] = new PictureBox();
    picBoard[i, j].Click += new EventHandler(
      (sender, e) => Debug.WriteLine(x.ToString() + " " + y.ToString()));
}

答案 1 :(得分:1)

你正在关闭循环变量,它们的值仅在lambda执行时循环已完成时进行评估,这就是你看到所有3的原因 - 改为制作本地副本:

for(int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
    {
        int localI = i;
        int localJ = j;
        picBoard[i, j] = new PictureBox();
        picBoard[i, j].Click += new EventHandler(
          (sender, e) => Debug.WriteLine(localI.ToString() + " " + localJ.ToString()));
    }

作为参考阅读"Closing over the loop variable considered harmful"了解为什么会发生这种情况。

答案 2 :(得分:1)

我喜欢这个问题!

那是因为事件处理程序是一个闭包,它捕获了i和j的值。这意味着当循环结束时,i和j的值都为3.所以当你点击时,它会显示3,3。

为了避免这种情况,你需要用这样的东西制作一个变量的本地副本(我不太了解.net语法)

var newI = i
var newJ = j
(sender, e) => {
   Debug.WriteLine(newI.ToString() + " " + newJ.ToString()));
}

这将使用正确的值制作一个j的副本。