Язык программирования C#9 и платформа .NET5
Console.WriteLine("***** Working with Timer type *****\n");Console.ReadLine();static void PrintTime(object state){Console.WriteLine("Time is: {0}",DateTime.Now.ToLongTimeString());}Обратите внимание, что метод
принимает единственный параметр типаPrintTime()и возвращаетSystem.Object. Это обязательно, потому что делегатvoidможет вызывать только методы, которые соответствуют такой сигнатуре. Значение, передаваемое целевому методу делегатаTimerCallback, может быть объектом любого типа (в случае примера с электронной почтой параметр может представлять имя сервера Microsoft Exchange Server для взаимодействия в течение процесса). Также обратите внимание, что поскольку параметр на самом деле является экземпляром типаTimerCallback, в нем можно передавать несколько аргументов, используяSystem.Objectили специальный класс либо структуру.System.ArrayСледующий шаг связан с конфигурированием экземпляра делегата
и передачей его объектуTimerCallback. В дополнение к настройке делегатаTimerконструкторTimerCallbackпозволяет указывать необязательный информационный параметр для передачи целевому методу делегата (определенный какTimer), интервал вызова метода и период ожидания (в миллисекундах), который должен истечь перед первым вызовом. Вот пример:System.ObjectConsole.WriteLine("***** Working with Timer type *****\n");// Создать делегат для типа Timer.TimerCallback timeCB = new TimerCallback(PrintTime);// Установить параметры таймера.Timer t = new Timer(timeCB, // Объект делегата TimerCallback.null, // Информация для передачи в вызванный метод.// (null, если информация отсутствует).0, // Период ожидания перед запуском (в миллисекундах).1000); // Интервал между вызовами (в миллисекундах).Console.WriteLine("Hit Enter key to terminate...");Console.ReadLine();В этом случае метод
вызывается приблизительно каждую секунду и не получает никакой дополнительной информации. Ниже показан вывод примера:PrintTime()***** Working with Timer type *****Hit key to terminate...Time is: 6:51:48 PMTime is: 6:51:49 PMTime is: 6:51:50 PMTime is: 6:51:51 PMTime is: 6:51:52 PMPress any key to continue ...Чтобы передать целевому методу делегата какую-то информацию, необходимо просто заменить значение
во втором параметре конструктора подходящей информацией, например:null// Установить параметры таймера.Timer t = new Timer(timeCB, "Hello From C# 9.0", 0, 1000);You can then obtain the incoming data as follows:static void PrintTime(object state){Console.WriteLine("Time is: {0}, Param is: {1}",DateTime.Now.ToLongTimeString(), state.ToString());}Использование автономного отбрасывания (нововведение в версии 7.0)
В предыдущем примере переменная
не применяется в каком-либо пути выполнения и потому может быть заменена отбрасыванием:Timervar _ = new Timer(timeCB, // Объект делегата TimerCallback.null, // Информация для передачи в вызванный метод// (null, если информация отсутствует).0, // Период ожидания перед запуском// (в миллисекундах).1000); // Интервал между вызовами// (в миллисекундах).Класс ThreadPool
Следующей темой о потоках, которую мы рассмотрим в настоящей главе, будет роль пула потоков. Запуск нового потока связан с затратами, поэтому в целях повышения эффективности пул потоков удерживает созданные (но неактивные) потоки до тех пор, пока они не понадобятся. Для взаимодействия с этим пулом ожидающих потоков в пространстве имен
предлагается классSystem.Threading.ThreadPoolЧтобы запросить поток из пула для обработки вызова метода, можно использовать метод
. Он имеет перегруженную версию, которая позволяет в дополнение к экземпляру делегатаThreadPool.QueueUserWorkItem()указывать необязательный параметрWaitCallbackдля передачи специальных данных состояния:System.Objectpublic static class ThreadPool{...public static bool QueueUserWorkItem(WaitCallback callBack);public static bool QueueUserWorkItem(WaitCallback callBack,object state);}Делегат
может указывать на любой метод, который принимает в качестве единственного параметра экземплярWaitCallback(представляющий необязательные данные состояния) и ничего не возвращает. Обратите внимание, что если при вызовеSystem.Objectне задается экземплярQueueUserWorkItem(), то среда .NET Core Runtime автоматически передает значениеSystem.Object. Чтобы продемонстрировать работу методов очередей, работающих с пулом потоков .NET Core Runtime, рассмотрим еще раз программу (в проекте консольного приложения по имениnull), в которой применяется типThreadPoolApp. На этот раз массив объектовPrinterне создается вручную, а методThreadбудет назначаться членам пула потоков:PrintNumbers()