Программирование с помощью таймеров обратного вызова
Программирование с помощью таймеров обратного вызова
Во многих приложениях возникает необходимость вызывать конкретный метод через регулярные промежутки времени. Например, в одном приложении может потребоваться отображение текущего времени в строке состояния с помощью некоторой вспомогательной функции. В другом приложении может понадобиться периодический вызов вспомогательной функции, выполняющей в фоновом режиме какие-то некритические задачи, например проверку поступления новых сообщений электронной почты. Для таких ситуаций можно использовать тип System. Threading.Timer в совокупности с соответствующим делегатом TimerCallback.
Для примера предположим, что нам нужно создать консольное приложение, которое ежесекундно выводит текущее время, пока пользователь не нажмет клавишу, завершающую выполнение этого приложения. Первым очевидным шагом здесь является создание метода, который будет вызываться типом Timer.
class TimePrinter {
static void PrintTime(object state) {
Console.WriteLine("Время: {0}", DateTime.Now.ToLongTimeString());
}
}
Этот метод имеет один параметр типа System.Object и возвращает void. Такая структура метода обязательна, поскольку делегат TimerCallback может вызывать только такие методы. Значение, передаваемое целевому методу делегата TimerCallback, может представлять любую информацию (так, в случае электронной почты это может быть имя сервера Microsoft Exchange, с которым требуется взаимодействие в ходе процесса). А так как параметр является типом System.Object, в действительности можно передать любое число аргументов, если использовать System.Array или пользовательский класс (структуру).
Следующим шагом является настройка экземпляра делегата TimerCallback и передача его объекту Timer. Кроме делегата TimerCallback, конструктор Timer позволяет указать дополнительную информацию (в виде System.Object) для передачи ее целевому объекту делегата, временной интервал опроса метода и время ожидания (в миллисекундах) до начала первого вызова, например:
static void Main(string[] args) {
Console.WriteLine("***** Работа с типом Timer ***** ");
// Создание делегата для типа Timer.
TimerCallback timeCB = new TimerCallback(PrintTime);
// Установка параметров таймера.
Timer t = new Timer(
timeCB, // Тип делегата TimerCallback.
null, // Информация для вызываемого метода или null.
0, // Время ожидания до старта.
1000); // Интервал между вызовами (в миллисекундах) .
Console.WriteLine("Нажмите «Enter» для завершения работы…");
Console.ReadLine();
}
В данном случае метод PrintTime() будет вызываться примерно каждую секунду и методу не передается никакой дополнительной информации. Чтобы передать целевому объекту делегата какую-то информацию, замените значение null второго параметра конструктора подходящим значением (например, "Привет"). Следующая модификация метода PrintTime() использует переданное значение.
static void PrintTime(Object state) {
Console.WriteLine("Время: {0}, Параметр: {1}", DateTime.Now.ToLongTimeString(), state.ToString());
}
На рис. 14.11 показан соответствующий вывод.
Рис. 14.11. Таймеры за работой
Исходный код. Проект TimerApp размещен в подкаталоге, соответствующем главе 14.