C#_6.ppt
- Количество слайдов: 26
C# делегаты Делегаты подобны указателям на функцию. Их можно использовать для вызова различных функций, причем выбор функции происходит во время выполнения программы. Делегат хранит имя метода, возвращаемый им тип и список параметров. Делегат состоит из двух частей : • Класс делегата • Объект этого класса После объявления класса делегата, создаются объекты этого класса. Эти объекты используются для хранения и вызова методов, соответствующих сигнатуре (тип возвращаемого значения и список параметров) метода делегата.
C# делегаты Формализм: [ур. _ доступа] delegate возвр. _ тип имя_класса_делегата (тип_параметра имя_параметра, …. . ); ур. _ доступа - public, protected, и т. д. возвр. _ тип – тип возвращаемый делегатом тип_параметра – тип передаваемого делегату параметра Пример объявления делегата public delegate double Deleg. Calc ( double accel, double time );
C# делегаты Использование. Объявлем класс public class Move. Calc { public static double FSpeed ( double acc, double time) { // выч. скорости double speed = acc * time; return(speed); } public static double Distance ( double acc, double time) {// выч. расстояния double dist = acc * Math. Pow(time, 2); return(dist); } }
C# делегаты class example { public void Main() { double accl = 10; double time = 5; // сиязываем с методом выч. скорости Delegate. Calc my. Deleg. Calc = new Delegate. Calc(Move. Calc. Fspeed); double speed = my. Deleg. Calc(accl, time ); // используем Console. Write. Line( “ V = “ + speed + “ m/sec”); // теперь связываем с методом выч. расстояния Delegate. Calc my. Deleg. Calc = new Delegate. Calc(Move. Calc. Distance); double dist = my. Deleg. Calc(accl, time); // используем Console. Write. Line( “ Distance = “ + dist + “ m”); } }
C# делегаты Многоадресные делегаты Можно при помощи одного делегата вызывать разные методы. При этом методы и делегат должны возвращать значение одно и тоже значение void. Тот же пример, но пусть методы класса не возвращают значения, а выводят его на экран. public delegate void Deleg. Calc 1 ( double accel, double time ); public class Move. Calc 1 { public static void FSpeed ( double acc, double time) { // выч. скорости double speed = acc * time; Console. Write. Line( “ V = “ + speed + “ m/sec”); ; }
C# делегаты public static void Distance ( double acc, double time) {// выч. расстояния double dist = acc * Math. Pow(time, 2); Console. Write. Line( “ Distance = “ + dist + “ m”); } } class example { public void Main() { double accl = 10; double time = 5; //далее заводим 2 объекта делегата Delegate. Calc 1 my. Deleg. Calc 1 = new Delegate. Calc(Move. Calc 1. Fspeed); Delegate. Calc 1 my. Deleg. Calc 2 = new Delegate. Calc(Move. Calc 1. Distance);
C# делегаты // создаем многоадресный делегат из двух предыдущих // операция сложения прегружена для делегатов !!! Delegate. Calc 1 my. Deleg. Calc. All = my. Deleg. Calc 1 + my. Deleg. Calc 2; // используем многоадресный my. Deleg. Calc. All(accl, time); } } Вызов методов объекта при помощи делегата Можно с помощью делегатов вызывать и методы объектов, а не только статические методы. public delegate string Delegate. Descr(); Этот делегат возвращает строку и не имеет параметров Объявим 2 класса. Первый описывает автомобиль, а второй водителя
C# делегаты public class Car { private string model; private int speed; public Car(string model, int speed) { this. model = model; this. speed = speed; } public string infocar() { return (“ Модель = “ + model + “ Скорость = “ + speed + “ km/hour”); } }
C# делегаты public class Person { private string name; private int age; public Person(string name, int age) { this. name = name; this. age = age; } public string infoperson() { return ( name + “ ” + age + “ лет “); } }
C# делегаты class Example { public static void Main() { Person my. Person = new Person(“Vasia”, 20); Delegate. Descr my. Delelegate. Descr = new Delegate. Descr(my. Person. infoperson); string persinfo = my. Delelegate. Descr(); Console. Write. Line(“ person = ” + persinfo); Car my. Car = new Car(“LADA”, 130); my. Delelegate. Descr = new Delegate. Descr(my. Car. infocar); string carinfo = my. Delelegate. Descr(); Console. Write. Line(“ car = ” + carinfo); } }
C# делегаты и события События позволяют одному объекту информировать другой объект о том, что-то происходит. События в С# это специальная разновидность делегатов. Можно определять свои события и обработчики событий. Формализм [ур. _доступа] event имя_класса_делегата имя_события Пусть некий реактор генерирует событие о том что его температура слишком высока. Обработчик события выводит об этом сообщение. Объявим это событие On. Meltdown, использующее класс делегата Meltdown. Handler public event Meltdown. Handler On. Meltdown;
C# делегаты Определим связанный с ним класс делегата public delegate void Meltdown. Handler ( object reactor; Meldown. Event. Args my. MEA; ) Все делегаты, вызывающие обработчики событий, должны возвращать void и принимать 2 параметра. Первый – должен иметь тип object и представлять объект вызвавший событие. Второй параметр – объект класса, унаследованного от System. Event. Args.
C# делегаты Определим класс для аргумента public class Meldown. Event. Args : Event. Args ( private string message; ; public Meldown. Event. Args(string message) { this. message = message; } public string Message // это свойство для получения поля message { get { return message; } } )
C# делегаты public class Reactor { //Это класс для реактора, который может перегреться private int temperature; // температура в реакторе //класс делегата для обработки события public delegate void Meltdown. Handler ( object reactor; Meldown. Event. Args my. MEA; ); public event Meltdown. Handler on. Meltdown; // объявление события public int Temperature { //это свойство для установки температуры set { temperature = value; if( temperature > 1000) { Meldown. Event. Args my. MEA = new Meltdown. Event. Args(“Реактор плавится !!!”); on. Meltdown(this, my. MEA); } } } )
C# делегаты В проверке на температуру создается объект, который будет аргументом для события с именем my. MEA. Строка о плавлении присваивается полю message этого объекта. Затем генерирутся событие on. Meltdown. Этому событию передаётся объект класса Reactor ( при помощи ссылки this) и объект – аргумент события my. MEA Событие on. Meltdown может быть отслежено и из любого другого объекта, который будет способен его обрабатывать. Например объявим класс Reactor. Monitor, объект которого будет использоваться для отслеживания событий объекта класса Reactor public class Reactor. Monitor { public Reactor. Monitor(Reactor my. Reactor) { my. Reactor. On. Meltdown += new Reactor. Meltdown. Handler( Display. Message); } public void Display. Message( object my. Reactor, Meldown. Event. Args my. MEA ) {
C# делегаты Console. Write. Line(my. MEA. Message ); } } Конструктор класса Reactor. Monitoк принимает параметр типа Reactor c именем my. Reactor. Этот параметр есть ссылка на объект, для которого будет отслеживаться событие on. Meltdown. Отслеживание события обеспечивается привязкой переданного параметра к обработчику Meltdown. Handler. Это в конструкторе записано так my. Reactor. On. Meltdown += new Reactor. Meltdown. Handler( Display. Message); Когда объект my. Reactor сгенерирует событие. On. Meltdown , то для его обработки будет вызван метод Display. Message(). Ранее класс Meltdown. Handler был определен как делегат, возвращающий значение void и принимающий два параметра – объект типа object и объект типа Meldown. Event. Args. Это в точности соответсвует сигнатуре метода Display. Message()
C# делегаты class Example { public static void Main() { Reactor my. Reactor = new Reactor(); // реактор // наблюдатель за реактором Reactor. Monitor my. Reactor. Monitor = new Reactor. Monitor (my. Reactor); Console. Write. Line(“ T = 100”); my. Reactor. Temperature = 100; // генерации нет Console. Write. Line(“ T = 500”); my. Reactor. Temperature = 500; // генерации нет Console. Write. Line(“ T = 2500”); my. Reactor. Temperature = 2500; // здесь генерируется событие On. Meltdown. // объект my. Reactor. Monitor замечает это событие // и вызывает метод Display. Message() } }
C# потоки Для создания потока надо создать экземпляр класса Thread. Конструктор этого класса имеет щдин параметр - экземпляр делегата Thread. Start. Описания классов потоков находится в System. Threading Делегат Thread. Start представляет метод, который будет вызываться для выполнения операций созданного потока. public static void Ametod() { // здесь код метода } public static void Main() { Thread t 2 = new Thread( new Thread. Start(Ametod)); } Здесь создается новый поток с именем t 2 При его запуске выполняется метод Ametod. Для запуска потока в основной программе надо вызвать метод Start для потока t 2
C# потоки using System; using System. Threading; class example { public static void Countdown() { for( int count = 1000; count > 0; count--) Console. Write((count. To. String() + “ “); } } public static void Main() { Thread t 2 = new Thread( new Thread. Start(Countdown)); //создали второй поток t 2. Start(); // запустили его Countdown(); // в это же время тот же метод выполняется в основном потоке }
C# потоки Результат – выводимая информация перемешана. Это из за того, что потоки используют один и тот же ресурс – консоль. Предсказать, когда процессор переключится с одного потока на другой невозможно. Но можно синхронизировать потоки с помощью некоторых способов. Потокам можно назначать приоритеты с помощью свойства Priority. Уровни содержатся в перечислении Thread. Priority • Lowest • Below. Normal • Above. Normal • Highest При создании все потоки имеют приоритет Normal, но его можно изменить
C# потоки public static void Main() { Thread t 2 = new Thread( new Thread. Start(Coundown)); //создали второй поток // установили ему высокий приоритет t 2. Prority = Thread. Priority. Highest; // установили текущему потоку (методу Main) низкий приоритет Thread. Current. Thread. Prority = Thread. Priority. Lowest; t 2. Start(); // запустили dnjhjq gjnjr Countdown(); // в это же время тот же метод выполняется в основном потоке } Результат изменился. Один потк кончился раньше, чем запустился другой. Однако нет гарантий, что поток с высоким приоритетом всегда будет заканчиваться до того, как запустится поток с с низким. Приоритет – это количество процессорного времени отводимого на поток, а не порядок выполнения потоков.
C# потоки Объекты класса Thread могут пребывать в разных состояниях. Для получения состояния потока используется свойство Thread. State Оно может вернуть • Unstarted - не запущен • Running – выполняется • Background – фоновый • Wiat. Sleep. Join – Поток заблокирован в результате вызова методов Wait, Sleep или Join • Suspend. Requested – Поток в состоянии подготовки на приостановку • Suspended – приостановлен • Stop. Requested - Поток в состоянии подготовки к остановке • Stopped – остановлен • Abort. Requested Запрос на отмену, но еще ее не получил • Abort – отменен После создания поток в состоянии Unstartedю После вызова метода старт переходит в состояние Running. Если после этого присвоить свойству Is. Background значение true, то перейдет в состояние Background Поток может быть в нескольких состояниях одновременно. Поэтому для прверки состояния используют логические конструкции
C# потоки Например так if( t. Thread. State & (Thread. State. Stopped | Thread. State. Unstarted | Thread. State. Aborted)) == 0) { Console. Write (“ Выполняется”); } Управление потоками Класс Timer позволяет выполнять потоки периодически Метод Join позволяет одному потоку ждать завершения другого Классы Lock, Inter. Locked, Monitor и Mutex позволяют координировать действия нескольких потоков и использование ресурсов несколькими потоками. При помощи класса Timer добавляется поток по принципу «вызвали и забыли» . При создании объекта Timer нужны 4 параметра • callback Делегат типа Timer. Callback представляющий метод, который будет вызываться по таймеру • state Объект, который передается методу Timer. Callback может быть null
C# потоки due. Time Количество миллисекунд перед первым срабатыванием таймера • Period период срабатывания таймера в миллисекундах class example { public static void Check. Time(Object state) { Console. Write. Line( Date. Time. Now); } public static void Main() { //делегат который будет вызываться объектом Timer. Callback tc = new Timer. Callback(Check. Time); Timer t = new Timer(tc, null, 1000, 2000); Console. Write. Line(“ Press Enter to exit”); int i = Console. Read() t. Dispose(); // освобождение ресурсов t = null; } } Метод tc выполняется в потоке, созданном системой, а не в потоке создавшем •
C# потоки Метод Join позволяет прикрепить один поток к другому. Это значит что первый поток будет ждать завершения второго, после чего будет запущен. class example { public static void Countdown() { for( int count = 1000; count > 0; count--) Console. Write((count. To. String() + “ “); } } public static void Main() { Thread t 2 = new Thread( new Thread. Start(Countdown)); //создали второй поток t 2. Start(); // запустили его t 2. Join(); // заблокировали первый до окончания второго // t 2. Join(5000); // если так, то блокировка первого максимально на 5 сек Countdown(); // метод будет выполняться после завершения второго потока }
C# потоки о
C#_6.ppt