Помощь в написании студенческих работ
Антистрессовый сервис

События. 
Программирование. 
Базовый курс с#

РефератПомощь в написанииУзнать стоимостьмоей работы

Метод run (), посылая сообщения о событиях, «ничего не знает» о том, кто будет получать эти сообщения, и как они будут обрабатываться. В технологии Windows-программирования принято говорить, что объект (в нашем примере не объект, а статический метод класса) публикует события, посылая сообщения о них. Другие объекты (в нашем примере это будут статические методы) могут подписаться на события. Метод… Читать ещё >

События. Программирование. Базовый курс с# (реферат, курсовая, диплом, контрольная)

Событие — средство, позволяющее объекту (или классу) послать во «внешний для объекта или класса мир» сообщение о переходе в некоторое новое состояние или о получении сообщения из внешнего источника. Так как на уровне программы все действия объектов и классов реализуются с помощью методов, то и посылка сообщения оформляется как оператор в теле некоторого метода. Синтаксически оператор посылки сообщения выглядит так:

имя_события (аргументы_для_делегата);

Разберем, о каком событии идет речь, и какую роль играет делегат, которому нужно предоставить аргументы.

Отметим, что объявление события может размещаться в классе, в структуре и в интерфейсе. Начнем с классов. Событие это член класса (или его объекта), вводимый объявлением:

модификаторыopt event имя_типа_делегата имя_события;

Модификатором может быть abstract, new, override, static, virtual, public, protected, private, internal.

event — служебное слово декларации события.

имя_события — идентификатор, выбираемый программистом в качестве названия конкретного члена, называемого переменной события. В практике программирования на C# принято начинать имена событий с префикса on.

имя_типа_делегата — имя того делегата-типа (его называют делегатом события или событийным делегатом), который должен представлять событию те методы, которые будут вызываться в ответ на посылку сообщения о событии.

Таким образом, событие — это член класса, имеющий тип делегата. Этот делегат-тип должен быть доступен в точке объявления события. Например, его определение должно находиться в том же файле. Событийный делегат-тип определяет для события сигнатуру и тип возвращаемого значения тех методов, которые могут быть вызваны в ответ на посылку сообщения о нем. Напомним, что сигнатура, и тип возвращаемого результата, вводимые типом делегата, определяют протокол для методов, представляемых делегатом.

В соответствии с этой сигнатурой определяются типы аргументов в операторе посылки сообщения о событии. В качестве типа возвращаемого значения в событийном делегате обычно используется void.

В качестве примера определим статический метод, посылающий через каждую секунду сообщение о событии. Чтобы такая возможность появилась, необходимо, чтобы в классе, которому принадлежит метод, было объявлено событие, и был доступен соответствующий этому событию делегат-тип. Соответствующие объявления могут быть такими: delegate void TimeHandler (); // объявление делегата-типа

static event TimeHandler onTime; 11 объявление события

Рекомендуется в название событийного делегата включать в качестве суффикса слово Handler (обработчик). Делегат TimeHandler в соответствии с его объявлением предназначен «представлять» методы без параметров, с возвращаемым значением типа void (ничего не возвращающие в точку вызова). Событие с именем onTime «настроено» на работу с экземплярами делегата TimeHandler.

В том же классе, где размещено объявление события и доступен делегат-тип, можно определить метод, через каждую секунду «генерирующий» посылку сообщений:

static void run ().

{ // процесс с событиями

Console.WriteLine («flnn выхода нажмите Ctrl+C!»); while (true).

{ // бесконечный цикл

onTimeQ; // посылка сообщения о событии

// задержка на секунду

System.Threading.Thread.Sleep (1000);

} }

В методе run () бесконечный цикл, в каждой итерации которого оператор onTime () посылает сообщение о событии, связанном с делегатом TimeHandler. Затем вызывается статический метод Sleep () класса Thread из пространства имен System.Threading. Назначение этого метода состоит в «задержке» процесса выполнения программы на количество миллисекунд, соответствующее значению аргумента. В данном случае задержка равна 1000 миллисекунд, т. е. одной секунде.

Метод run (), посылая сообщения о событиях, «ничего не знает» о том, кто будет получать эти сообщения, и как они будут обрабатываться. В технологии Windows-программирования принято говорить, что объект (в нашем примере не объект, а статический метод класса) публикует события, посылая сообщения о них. Другие объекты (в нашем примере это будут статические методы) могут подписаться на события.

Подписка на получение сообщений о событии в языке C# предусматривает следующие действия:

  • • создание экземпляра того делегата, на который настроено событие;
  • • подключение экземпляра делегата к событию.

Обычно эти два действия объединяют в одном операторе следующего формата:

имя_события += new имя_типа_делегата (имя_метода);

Условие применимости подписки на событие — наличие и доступность метода, который будет вызван для обработки события. Имя этого метода используется в качестве аргумента конструктора делегата. Само собой, и делегат события, и имя события должны быть доступны в месте подписки.

При создании экземпляра делегата операцию new и явное обращение к конструктору можно заменить именем метода:

имя_события += имя_метода;

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

Предположим, что «принимать сообщения» о событиях в методе run () должен метод Main () того же класса, в котором определен метод run (). Пусть обработчиками сообщения о событии должны быть два метода с заголовками:

static void one () static void two ().

Тогда метод Main может быть таким (программа 1708.cs):

static void Main ().

{

onTime += new TimeHandler (one); // подписка на событие onTime += new TimeHandler (two); // подписка для метода two run (); // запуск процесса

У

Остальное, т. е. функциональность программы в целом, зависит от возможностей и особенностей методов опе () и two (). В следующей ниже программе метод опе () выводит в консольное окно дату и посекундно изменяющееся значение времени. Метод two () в начале той же строки выводит порядковый номер события. Номер изменяется каждую секунду (при каждом обращении к методу).

// 1708.cs — статические события и статические методы using System;

delegate void TimeHandlerQ; // объявление делегата-типа class test_cs {.

static event TimeHandler onTime; 11 объявление события static void run ().

{ // процесс с генерацией событий

Console.WriteLine ('^H выхода нажмите Ctrl+C!"); while (true).

{ // бесконечный цикл

onTime (); // посылка сообщения о событии

// задержка на 1 секунду

System.Threading.Thread.Sleep (1000);

} }

static void Main ().

{

onTime += new TimeHandler (one); 11 подписка на событие onTime += two; 11 для метода two.

run (); // запуск процесса

У

static void one ().

{ // приемник сообщения

string newTime = DateTime.Now.ToString ();

Console.Write (M {0}", newTime);

}

static int count = 0; static void two ().

{ // приемник сообщения

Console.Write («{0}», count++);

} }

Результат выполнения программы на 6-й секунде:

Для выхода нажмите Ctrl+C!

6 11.11.2018 12:59:49.

В тексте программы обратим внимание на вывод указания пользователю:

Console.WriteLine («Ana выхода нажмите Ctrl+C!»);

Сочетание клавиш Ctrl и С приводит к незамедлительному прекращению выполнения программы. Чтобы не «затемнять» основную схему программы, иллюстрирующей только механизм работы с событиями, в нее не введены никакие средства диалога с пользователем.

В строке-аргументе метода консольного вывода Write () управляющая эскейп-последовательность г обеспечивает при каждом обращении переход в начало строки дисплея. Тем самым вывод все время выполняется с начала одной и той же строки, изображение на которой обновляется ежесекундно.

В методе опе () используется свойство Now класса Data.Time. Его назначение — вернуть текущее значение даты и времени. Применение метода ToStringO позволяет представить эти значения в виде одной строки, которая затем выводится на дисплей.

Для подсчета событий (секунд) определена статическая переменная int count. Ее значение выводит и затем увеличивает на 1 метод two ().

В рассмотренном примере делегат-тип объявлен вне классов, и все методы определены как статические — генерацию событий выполняет статический метод run (), подписаны на события два других статических метода. Таким образом, с помощью механизма событий взаимодействуют не объекты, а методы одного класса test_cs. Кроме того, в объявлении делегата-типа отсутствуют параметры. Поэтому при посылке сообщения о событии методы обработки не получают никакой информации из точки возникновения события.

Более общий случай — событие создается объектом, а в других объектах (в объектах других классов) имеется возможность реагировать на эти события. Как мы уже показали, к одному событию может быть «приписано» несколько обработчиков и все они будут вызваны при наступлении события.

Механизм работы с событиями предусматривает несколько этапов.

  • 1. Объявление делегата-типа, задающего протокол для тех (еще неизвестных на данном этапе) методов, которые будут вызываться при обработке события.
  • 2. Определение переменной события, имеющей тип делегата события.
  • 3. Определение генератора события (средства посылки сообщения), с указанием аргументов, при необходимости информирующих получателей о состоянии объекта, пославшего сообщение.
  • 4. Определение методов обработки события. Сигнатура и тип результата каждого метода должны соответствовать типу делегата события.
  • 5. Создание экземпляра того делегата, на который «настроено» событие. Аргумент конструктора — имя метода обработки.
  • 6. Подключение экземпляра делегата к переменной события.

Перечисленные этапы обычно относятся к разным классам программы. И этих разных классов по меньшей мере два. Класс, обрабатывающий события, должен содержать методы обработки или, по крайней мере, иметь доступ к этим методам. В нем реализуются этапы 4, 5, 6. Второй класс — это класс, генерирующий события, он реализует этапы 1, 2, 3.

Зачастую в программе присутствует третий класс, управляющий процессом на более высоком уровне. В разных задачах его называют супервизором, монитором, диспетчером и т. п. При наличии такого класса и двух подчиненных — класса генерации и класса обработки событий — схема работы супервизора сводятся к следующим шагам:

  • 1. Создать объект класса генерации событий.
  • 2. Создать объект класса обработки событий (этого может не потребоваться, если метод обработки является статическим).
  • 3. Создать экземпляр делегата, «настроив» его на метод класса обработки событий.
  • 4. Подключить экземпляр делегата к переменной события (принадлежащей объекту класса генерации).
  • 5. Передать управление объекту класса генерации событий (какомулибо из его методов, генерирующих события).

Далее все выполняется в соответствии с общими принципами событийного управления.

В качестве примера рассмотрим программу с делегатом и четырьмя классами. Класс Sorting содержит метод с двумя вложенными циклами, который сортирует в порядке возрастания одномерный целочисленный массив. В процессе сортировки подсчитывается количество перестановок значений элементов. При каждом завершении внутреннего цикла формируется событие, передающее «во внешний мир» количество выполненных перестановок, размер массива и счетчик итераций внешнего цикла. Для работы с событиями в классе объявлено событие onSort, имеющее тип внешнего делегата SortHandler.

Класс View содержит метод обработки события. Метод выводит на консоль значение счетчика перестановок.

Класс Display визуализирует динамику процесса сортировки — выводит на консоль имитацию элемента управления ProgressBar.

Метод Main () управляющего класса Controller в соответствии с общей схемой создает объект класса, генерирующего события, создает объект класса-обработчика (View). Затем подключает к переменной события два наблюдателя — два безымянных экземпляра делегата SortHandler. И, наконец, управление передается генератору событий — методу сортировки sort (), принадлежащего объекту класса Sorting.

// 1709.cs — события и сортировка using System; using System. Text;

// Объявление делегата-типа:

public delegate void SortHandler (long cn, int si, int kl); class Sorting.

{ // класс сортировки массивов int size; // размер массива int [ ] ar; // ссылка на массив

public long count; 11 счетчик обменов при сортировке public event SortHandler onSort; // объявление события public Sorting (int[] Is).

{ // конструктор size = Is. Length; count = 0; ar = Is;

}

public void sort ().

{ // сортировка с посылкой извещений int temp;

for (int i = 0; i < size — 1; i++).

{

for (int j = i + 1; j ar[j]).

{

temp = ar[i]; ar[i] = a r[j]; a r[j] = temp; count++;

}

if (onSort ≠ null).

onSort (count, size, i); // генерация события

}

}

}

class View.

{ // Обработчик событий в объектах:

public void nShow (long n, int si, int kl).

{ Console. Write («» + n); }.

}

class Display.

{ // Обработчик событий в этом классе static int len = 30; static string st = null;

public static void barShow (long n, int si, int kl).

{

int pos = Math. Abs ((int)((double)kl /si * len)); string si = new string ('u258c', pos); string s2 = new string ('-', len — pos — 1) +.

'u25c4'; // Unicode для треугольника;

st = si + 'u258c' + s2; //'u258c' - код прямоугольника Console. Write («» + st);

} }

class Controller.

{

static void Main ().

{

Random ran = new Random (55); int[] ar = new int[19 999]; for (int i = 0; i < ar. Length; i++) ar[i] = ran. Next ();

Sorting run = new Sorting (ar);

View watch = new View (); // Создан объект run. onSort += new SortHandler (Display.barShow); run. onSort += new SortHandler (watch.nShow); run. sort ();

Console.Write (««);

} }

Результат выполнения программы:

100 372 610 llllllllllllllllllllllllllllll;

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

При генерации события целесообразно проверять значение переменной события. Эта переменная остается равной null, если на событие нет ни одной подписки.

Обратите внимание также на тот факт, что генерация события, в отличие от генерации исключения, оформляется как обращение к методу. Благодаря этому после обработки события управление автоматически возвращается в точку, непосредственно следующую за оператором генерации события.

Контрольные вопросы и задания

  • 1. В чем основное назначение делегата?
  • 2. Назовите этапы создания и применения делегатов.
  • 3. Члены каких видов могут присутствовать в делегате-типе?
  • 4. Объясните назначение элементов объявления делегата-типа.
  • 5. Как объявить ссылку с типом делегата?
  • 6. Как создать экземпляр делегата?
  • 7. Как аргументы можно использовать при обращении к конструктору делегата?
  • 8. Где может размещаться объявление делегата-типа?
  • 9. Назовите варианты инициализации переменной с типом делегата.
  • 10. Каковы возможности свойств Method и Target?
  • 11. Для чего применяются массивы делегатов?
  • 12. Что такое многоадресный экземпляр делегата?
  • 13. Какие средства поддерживают работу с многоадресными экземплярами делегатов?
  • 14. Что такое механизм обратного вызова?
  • 15. Как используются делегаты для организации обратных вызовов?
  • 16. Что такое анонимный метод?
  • 17. Как специфицируется сигнатура анонимного метода?
  • 18. Приведите пример размещения анонимного метода в обращении к методу, требующему обратных вызовов.
  • 19. Перечислите сходства и отличия лямбда-выражений и анонимных методов.
  • 20. Объясните синтаксис записи лямбда-выражений.
  • 21. Когда лямбда-выражение можно записать без параметров?
  • 22. Что такое захваченная переменная?
  • 23. В какой момент определяется значение захваченной переменной?
  • 24. Что такое событие в языке С#?
  • 25. Объясните синтаксис оператора посылки сообщения.
  • 26. Приведите формат объявления события.
  • 27. Что такое переменная события?
  • 28. Что определяет делегат, указанный в объявлении события?
  • 29. Какие действия предусматривает подписка на события?
  • 30. Назовите этапы работы с событиями.
Показать весь текст
Заполнить форму текущей работой