倒数计时器

时间:2020-05-04 05:16:30

标签: c# timer

我正在尝试倒计时!

这是我尝试过的计时器代码:

a.find()

目前,我的代码在控制台中将其打印出来: enter image description here

但是,我希望我的代码倒数秒,并且在输出中仅使用一行。


更新

我正在尝试倒计时!

这是我尝试过的计时器代码:

class WorkingWithTimer
        {
            public static int input()
            {
                int numberOfSeconds;
                do
                {
                    Console.WriteLine("How many seconds would you like the test to be? Please type a number divisible by 10!");
                    int.TryParse(Console.ReadLine(), out numberOfSeconds);
                } while (numberOfSeconds % 10 != 0);
                return numberOfSeconds;  
            } 
            
            public static void CountTimer(object time)
            {
                Console.WriteLine($"TimeLeft: {time}");
                Thread.Sleep(1000);
            }
            public static void Main(string[] args)
            {
                int numberOfSeconds = input();
                Timer t = new Timer(CountTimer, numberOfSeconds, 1, 1000);
                Thread.Sleep(1000);
                t.Dispose();
            }
        }

目前,我的代码在控制台中将其打印出来: enter image description here

但是,我希望我的代码在不创建换行符的情况下倒计时,例如将10更改为第一行的9,以此类推。

3 个答案:

答案 0 :(得分:2)

如果我对您使用的自定义Timer类的推论是正确的,则它是:

  • 有一个构造函数,该构造函数接受一个在每个时间间隔都将被调用的委托
  • 从您身上取走一个物体,并在每次滴答时将其传递回给您
  • 不确定1代表什么,请避免在代码中添加幻数
  • 猜测1000是时间间隔(以毫秒为单位)。同样,请避免在代码中使用无注释的纯数字或带有名称
  • 的常量var
  • 无需启动就可以在其构造函数之外进行同步操作

因为它始终需要向您提供相同的对象,所以您需要稍微更改代码,以便传递的对象不是值类型;如果不这样做,则将递减CountTimer中的int,但不会有任何变化,因为您不会修改原始引用所指向的数据。您可能不能只添加ref关键字,因为自定义计时器不会被编程为使用它来调用。因此,让我们对其进行调整,以便我们传递一个int数组:

        public static void CountTimer(object time)
        {
            var x = (int[])time;
            x[0]--;
            Console.WriteLine($"TimeLeft: {x[0]}");
            //Thread.Sleep(1000); you don't need to sleep for a second; it will make your timer count every two seconds!
        }
        public static void Main(string[] args)
        {
            int[] numberOfSeconds = new int[1];
            numberOfSeconds[0] = input();
            Timer t = new Timer(CountTimer, numberOfSeconds, 1, 1000);
            Thread.Sleep(1000);
            t.Dispose();
        }

如上所述,所有这些取决于您的Timer类,其中有一些自定义类,该类采用方法名称来每x毫秒调用一次,并始终为它提供相同的对象。没有任何地方会减少您的int时间,因此它一次又一次地说了30。我们不能像您一样将time强制转换为一个int并递减它,因为它不会导致Timer保留的原始int发生变化。取而代之的是,如果让它使Timer持有的对象是一个int数组,那么该数组对象本身就不会改变,但是存储在第一个插槽中的值可以递减

FWIW,我认为这是创建倒数计时器的一种非常复杂的方法,并且也阻碍了用户执行其他任何操作。如果这很适合您的游戏,那么很好,但是如果您希望他们在30秒内采取行动,那么我认为您正在使用的Timer类会遇到麻烦

答案 1 :(得分:1)

由于您使用的是System.Threading.Timer和控制台应用程序,因此您将需要一种告诉控制台应用程序等待定时器完成的方法。调用Thread.Sleep(1000);不会削减它-特别是因为您正在等待至少10秒。

使控制台应用程序等待的简单方法是使用AutoResetEvent

private static AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

现在您可以在_autoResetEvent.WaitOne();方法中调用Main,它将等待直到您在_autoResetEvent.Set();方法中调用CountTimer

现在,使用System.Threading.Timer,您可以在构造计时器时传递状态,但是该状态不会更新,因此您需要添加另一个字段来跟踪秒数滴答作响的。

private static int _numberOfSeconds = 0;

此外,当您在框架中花费时间做任何事情,并且可以选择传递int或使用TimeSpan之间时,应始终选择TimeSpan,因为这会使您的代码更复杂更具可读性。

您的MainCountTimer方法现在看起来像这样:

public static void Main(string[] args)
{
    _numberOfSeconds = input();
    using (var t = new Timer(CountTimer, null, TimeSpan.Zero, TimeSpan.FromSeconds(1.0)))
    {
        //Thread.Sleep(1000); No Need To Sleep Here!
        _autoResetEvent.WaitOne();
    }
    _autoResetEvent.Dispose();
}

public static void CountTimer(object state)
{
    Console.WriteLine($"TimeLeft: {_numberOfSeconds--}");
    //Thread.Sleep(1000); No Need To Sleep Here!
    if (_numberOfSeconds < 0)
    {
        _autoResetEvent.Set();
    }
}

请注意,由于示例代码没有真实状态,因此我将null传递为Timer的状态。

使用10输入运行此代码时得到的输出是:

How many seconds would you like the test to be? Please type a number divisible by 10!
TimeLeft: 10
TimeLeft: 9
TimeLeft: 8
TimeLeft: 7
TimeLeft: 6
TimeLeft: 5
TimeLeft: 4
TimeLeft: 3
TimeLeft: 2
TimeLeft: 1
TimeLeft: 0

答案 2 :(得分:-1)

您应该查看this以获得更多信息。基本上,您可以这样做:

class StatusChecker {
    private int numberOfSecondsLeft;

    public StatusChecker(int numberOfSecondsLeft) {
        this.numberOfSecondsLeft = numberOfSecondsLeft;
    }

    public void CountDown(object state) {
        Console.Write($"{this.numberOfSecondsLeft},");

        var autoEvent = (AutoResetEvent)state;
        if (--this.numberOfSecondsLeft == 0) {
            autoEvent.Set();
        }
    }
}

class Program {
    static void Main(string[] args) {
        var numberOfSeconds = input();
        var autoEvent = new AutoResetEvent(false);

        var checker = new StatusChecker(numberOfSeconds);
        Console.WriteLine("Time left:");
        var t = new Timer(checker.CountDown, autoEvent, 0, 1000);
        autoEvent.WaitOne();
        t.Dispose();
    }

    public static int input() {
        int numberOfSeconds;
        do {
            Console.WriteLine("How many seconds would you like the test to be? Please type a number divisible by 10!");
            int.TryParse(Console.ReadLine(), out numberOfSeconds);
        } while (numberOfSeconds % 10 != 0);
        return numberOfSeconds;
    }
}