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”)。
答案 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的副本。