Создание таймера обратного отсчета - PullRequest
0 голосов
/ 04 мая 2020

Я пытаюсь сделать таймер обратного отсчета!

Вот код таймера, который я пробовал:

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

Однако я хочу, чтобы мой код отсчитывал секунды и использовал только одну строку в выводе.


Обновление

Я пытаюсь сделать таймер обратного отсчета!

Вот код таймера, который я пробовал:

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)
            {
                var x = (int[])time;
                x[0]--;
                Console.WriteLine($"TimeLeft: {x[0]}");
            }
            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();
            }
        }

В данный момент мой код выводит его на консоль: enter image description here.

Однако я хочу, чтобы мой код работал в обратном отсчете без создания новой строки, например, 10 изменится на 9 в первой строке и т. Д.

Ответы [ 3 ]

2 голосов
/ 04 мая 2020

Если то, что я вывел относительно того пользовательского класса Timer, которое вы используете, является правильным, то оно:

  • имеет конструктор, который принимает делегат, который должен вызываться каждый интервал
  • забирает у вас объект и передает его вам каждый раз, когда он помечается
  • не уверен, для чего нужна цифра 1, избегайте магических c чисел в вашем коде
  • , предполагая, что 1000 - это интервал в миллисекундах. Опять же, избегайте использования в коде простых чисел без комментариев или константной переменной с именем
  • работает синхронно вне своего конструктора, даже не будучи запущенным

, поскольку он предоставляет один и тот же объект возвращаясь к вам все время, вам нужно будет немного изменить свой код, чтобы передаваемый объект не являлся типом значения; если вы этого не сделаете, вы уменьшите int в CountTimer, но ничего не изменится, потому что вы не будете изменять данные, на которые указывает исходная ссылка. Вы, вероятно, не можете просто добавить ключевое слово 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 миллисекунд и продолжает снабжать его тем же объектом. Нигде не уменьшалось время, которое у вас есть, поэтому просто повторялось 30 раз. Мы не можем просто привести time к вашему значению int и уменьшить его, потому что это не приведет к изменению исходного int, удерживаемого Timer. Если вместо этого мы сделаем так, чтобы объект, удерживаемый Таймером, представлял собой массив int, то сам объект массива никогда не изменится, но значение, сохраненное в первом слоте, может быть уменьшено

FWIW, я думаю, что это довольно сложный способ просто создать таймер обратного отсчета, и это также блокирует пользователя от каких-либо других действий. Если это подходит для вашей игры, тогда хорошо, но если вы ожидаете, что они сделают ход в течение 30 секунд, я думаю, у вас возникнут проблемы с этим классом Timer, который вы используете

1 голос
/ 04 мая 2020

Поскольку вы используете 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, так как это делает ваш код намного более читабельным.

Your * Методы 1024 * & CountTimer теперь могут выглядеть следующим образом:

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
0 голосов
/ 04 мая 2020

Вы должны просмотреть это для получения дополнительной информации. В принципе, вы могли бы сделать это:

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...