当代码从 keydown 事件移动到函数中时,c# 变量会重置 - 谁能解释为什么?

c# variables reset when code is moved from keydown event into a function - can anyone explain why?

我在 VS Express 2010 中使用 C# windows 表单应用程序。我正在使用一些代码来进行学习。我有一个表单对象,我想通过按键不断地向一个方向移动 - 原始代码可以正常工作。

在尝试通过将 "movement" 的代码移动到函数中来整理它的过程中,代码不再像以前那样工作。现在,我的对象不再沿所选方向从其当前位置移动,而是在每次按下键时重置其位置。我想知道为什么会这样,因为我所做的更改绝对是最小的。请看代码:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{          
    if (e.KeyCode == Keys.Down)
    {
        direction = 4;
    }
    if (e.KeyCode == Keys.Up)
    {
        direction = 2;
    }
    if (e.KeyCode == Keys.Right)
    {
        direction = 3;
    }
    if (e.KeyCode == Keys.Left)
    {
        direction = 1;
    }

    while (direction != 0)
    {

        Application.DoEvents();
        if (direction == 1)
        {
            X = X - 1;
        }
        else if (direction == 2)//up
        {
            Y = Y - 1;
        }
        else if (direction == 3)
        {
            X = X + 1;
        }
        else if (direction == 4)//down
        {
            Y = Y + 1;
        }

        Thread.Sleep(100);
        label1.Location = new Point(X, Y);
    }
}

当我将 while 循环移动到移动函数中时,变量 X 和 Y 在每次按键时都重置为 0。此代码如下所示:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{          
  if (e.KeyCode == Keys.Down)
  {
      direction = 4;
  }

  if (e.KeyCode == Keys.Up)
  {
      direction = 2;
  }

  if (e.KeyCode == Keys.Right)
  {
      direction = 3;
  }

  if (e.KeyCode == Keys.Left)
  {
      direction = 1;
  }

  movement(X, Y, direction);
}

我觉得我在这里遗漏了一些明显的东西,但我不明白为什么它的行为有所不同。感谢您的帮助:)

编辑 1:移动函数的代码:

    movement(int X, int Y, int direction)
    {
        while (direction != 0)
        {
            Application.DoEvents();
            if (direction == 1)
            {
                X = X - 1;
            }
            else if (direction == 2)//up
            {
                Y = Y - 1;
            }
            else if (direction == 3)
            {
                X = X + 1;
            }
            else if (direction == 4)//down
            {
                Y = Y + 1;
            }
            Thread.Sleep(100);
            label1.Location = new Point(X, Y);

        }            
    }

我想您的 movement 方法更改了作为参数提供的 XY。但是,参数XY传递的是'by value',而不是'by reference'。

如果你想让这个工作,你要么必须使用 class 变量,并删除方法调用中的参数,要么使用 ref,我将演示:

movement(ref X, ref Y, direction);

并且:

private void movement(ref int X, ref int Y, int direction)
{ }
private void Form1_KeyDown(object sender, KeyEventArgs e)
{          
    if      (e.KeyCode == Keys.Down)  direction = 4;
    else if (e.KeyCode == Keys.Up)    direction = 2;
    else if (e.KeyCode == Keys.Right) direction = 3;
    else if (e.KeyCode == Keys.Left)  direction = 1;

    while (direction != 0)
    {
        Application.DoEvents();

        if      (direction == 1) X--;
        else if (direction == 2) Y--;
        else if (direction == 3) X++;
        else if (direction == 4) Y++;

        Thread.Sleep(100);
        label1.Location = new Point(X, Y);
    }
}

可以改写:

private void SetDirection(KeyEventArgs e)
{
    if      (e.KeyCode == Keys.Down)  direction = 4;
    else if (e.KeyCode == Keys.Up)    direction = 2;
    else if (e.KeyCode == Keys.Right) direction = 3;
    else if (e.KeyCode == Keys.Left)  direction = 1;
}

private void ApplyMovement()
{
    while (direction != 0)
    {
        Application.DoEvents();

        if      (direction == 1) X--;
        else if (direction == 2) Y--;
        else if (direction == 3) X++;
        else if (direction == 4) Y++;

        Thread.Sleep(100);
        label1.Location = new Point(X, Y);
    }
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{          
    SetDirection(e);

    ApplyMovement();
}

您必须了解变量 XYdirection 是 class 成员,因此可以从 [=39= 中的任何位置访问它们],并且当您调用 movement(X, Y, direction) 时,movement 将使用这些变量的 副本 ,因此当您在 movement 中执行 X = X + 1方法,您实际上并没有更改 class 的 X 值,而只是更改了它的 copy。 这意味着变量 X 和 Y(即 class 成员)不会在每次按键时 重置 为 0。事实上 它们永远不会设置为任何其他值.

请注意,您也可以使用 switch 语句代替所有那些 ifs。

switch (direction)
{
    case 1: X--; break; // left
    case 2: Y--; break; // up
    case 3: X++; break; // right
    case 4: Y++; break; // down
}