等待而不休眠?

4
我想要做的是启动一个函数,然后将一个布尔值更改为false,等待一秒钟,再将其设置为true。然而,我希望在函数不必等待的情况下完成它,我应该怎么做?
我只能使用Visual C# 2010 Express。
下面是有问题的代码。我正在尝试接收用户输入(比如向右箭头),并相应地移动,但在角色移动时不允许进一步的输入。
        x = Test.Location.X;
        y = Test.Location.Y;
        if (direction == "right") 
        {
            for (int i = 0; i < 32; i++)
            {
                x++;
                Test.Location = new Point(x, y);
                Thread.Sleep(31);
            }
        }
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        int xmax = Screen.PrimaryScreen.Bounds.Width - 32;
        int ymax = Screen.PrimaryScreen.Bounds.Height - 32;
        if (e.KeyCode == Keys.Right && x < xmax) direction = "right";
        else if (e.KeyCode == Keys.Left && x > 0) direction = "left";
        else if (e.KeyCode == Keys.Up && y > 0) direction = "up";
        else if (e.KeyCode == Keys.Down && y < ymax) direction = "down";

        if (moveAllowed)
        {
            moveAllowed = false;
            Movement();
        }
        moveAllowed = true;  
    }

1
你认为等待和休眠的区别是什么?你希望在此期间运行其他代码吗? - Ben Voigt
@BenVoigt 是的,我确实想同时运行其他代码。 - UltimateAlloy
@BrianTompsett请不要重新激活旧问题以进行微不足道的编辑。一次性修复所有问题。 "编辑"标记不属于此处,"我已解决此问题"也不应出现在问题中(已接受的答案表明了这一点),而且措辞还有很大的改进空间。 - nobody
2个回答

11
使用 Task.Delay 方法:
Task.Delay(1000).ContinueWith((t) => Console.WriteLine("I'm done"));

或者

await Task.Delay(1000);
Console.WriteLine("I'm done");

对于旧的框架,您可以使用以下内容:

var timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate { Console.WriteLine("I'm done"); };
timer.AutoReset = false;
timer.Start();

根据问题描述的示例:

class SimpleClass
{
    public bool Flag { get; set; }

    public void function()
    {
        Flag = false;
        var timer = new System.Timers.Timer(1000);
        timer.Elapsed += (src, args) => { Flag = true; Console.WriteLine("I'm done"); };
        timer.AutoReset = false;
        timer.Start();
    }
}

错误1:'System.Threading.Tasks.Task'不包含'Delay'的定义 C:\Users\Thomas\Documents\Visual Studio 2010\Projects\meh\meh\Form1.cs 57 22 meh - UltimateAlloy
1
@UltimateAlloy:尝试使用更高版本的.NET。Task.Delay是在.NET 4.5中引入的。此外,如果您使用C# 5,可以使用async/await... - Jon Skeet
修改过了,还有其他的想法吗? - UltimateAlloy
@UltimateAlloy,我已经添加了一个示例。希望它能满足你的需求。 - ixSci
@ixSci,由于我在某些方面并不是最聪明的人,而且在我的情况下很难理解,因此我已经附上了一些代码以提供更多的上下文信息,对于我的理解不足,我感到抱歉。 - UltimateAlloy
显示剩余2条评论

0

我知道已经有一个答案被接受了,我也喜欢ixSci的答案,他建议使用Timer对象来实现OP的目标。

然而,特别是使用System.Timers.Timer会引入线程考虑因素。为了确保在这种情况下的正确性,需要更多的代码来正确同步布尔标志值。基本上,在任何读取或写入标志的地方,代码区域都需要定义一个锁语句。

它应该看起来像这样:

private final object flagLock = new object();
private bool moveAllowed = true;
private System.Timers.Timer timer = new System.Timers.Timer();

public Form1()
{
    this.timer.Interval = 1000;
    this.timer.AutoReset = false;
    this.timer.Elapsed += (s, e) =>
    {
        // this DOES NOT run on the UI thread, so locking IS necessary to ensure correct behavior.
        this.timer.Stop();
        lock (this.flagLock) {
            this.moveAllowed = true;
        }
    };
}

// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    // Locking is necessary here too.
    lock (this.flagLock) {
        if (this.moveAllowed)
        {
            this.moveAllowed = false;
            Movement();
            this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
        }
    }
}

或者,为了避免考虑线程问题,也许OP可以考虑使用不同版本的Timer类。即:System.Windows.Forms.Timer。这样,布尔标志将始终在UI线程上读取/写入,并且不需要任何额外的锁定来确保正确性。

在这种情况下,代码看起来应该像这样:

private bool moveAllowed = true;
private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

public Form1()
{
    this.timer.Interval = 1000;
    this.timer.Tick += (s, e) =>
    {
        // this runs on the UI thread, so no locking necessary.
        this.timer.Stop(); // this call is necessary, because unlike System.Timers.Timer, there is no AutoReset property to do it automatically.
        this.moveAllowed = true;
    };
}

// The code in this event handler runs on the UI thread.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (this.moveAllowed)
    {
        this.moveAllowed = false;
        Movement();
        this.timer.Start(); // wait 1 second to reset this.moveAllowed to true.
    }
}

我明白了,除了类的名称之外,我还需要更改其他内容吗?例如值等等?你能给我发送一些示例代码吗? - UltimateAlloy
@UltimateAlloy:我编辑了我的答案,提供了两种选项的示例代码。 - sstan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接