Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
16 вариант.doc
Скачиваний:
13
Добавлен:
02.09.2019
Размер:
182.27 Кб
Скачать

5. «Объектно-ориентированное программирование»

16. Организация взаимодействия объектов с помощью делегатов и событий. Последовательность создания события в классе.

Одной из центральных задач, которые приходится решать разработчикам библиотек классов для управления элементами пользовательского интерфейса, является задача взаимодействия между разными объектами. Элементы пользовательского интерфейса посылают приложению информацию о действиях пользователя. Проблема заключается в том, чтобы объект, получивший информацию о действии пользователя, как правило, должен передать эту информацию другим объектам приложения.

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

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

В целях реализации механизма событий в языке программирования C# предусмотрен так называемый механизм делегатов. Преимущество делегатов языка C# состоит в большей управляемости и безопасности кода (в частности, в C# существует возможность контроля соответствия типов параметров делегатов и логики вызова).

Делегаты являются ссылками на методы, инкапсулирующими настоящие указатели и предоставляющими удобные сервисы для работы с ними. Ссылки представляют собой объекты соответствующего типа. Все делегаты являются объектами типа System.Delegate или System.MulticastDelegate, который является производным от первого.

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

Эта возможность очень удобна для поддержки событий, поскольку позволяет без использования дополнительных механизмов присоединить к событию несколько функций обработчиков. Фактически, делегат представляет собой объект — черный ящик, скрывающий в своих недрах указатели на функции. Важно понять, что делегаты, по сути дела, ничем не отличаются от обычных пользовательских объектов. Главная их особенность состоит лишь в том, что они имеют поддержку со стороны среды исполнения. Об их свойствах, в отличие от обычных объектов, знают даже компиляторы, предоставляющие удобные специальные сервисы для работы с ними.

Все методы в среде .NET можно разделить на две группы: статические (static) и экземплярные (instance). Если делегат ссылается на статический метод, то все действительно просто. Так как в этом случае есть вся необходимая для вызова метода информация: адрес метода и параметры. Если же делегат ссылается на экземплярный метод, то задача усложняется. Чтобы вызвать экземплярный метод, делегату необходимо знать ссылку на объект, к которому привязан данный конкретный метод. Оказывается, что эта ссылка хранится в самом объекте делегата и указывается при его создании. На протяжении всей жизни объекта делегата данная ссылка не изменяет своего значения, она всегда постоянна и может быть задана только при его создании. Таким образом, вне зависимости от того, ссылается ли делегат на статическую функцию или на экземплярный метод, обращение к нему извне ничем отличаться не будет. Всю необходимую функциональность обеспечивает сам делегат, вкупе со средой исполнения. Это очень удобно, поскольку множество разных делегатов можно привязывать к одному событию.

Следующие процедуры описывают реализацию событий в классе. Первая процедура реализует событие, которое не имеет связанных данных; она использует классы System.EventArgs и System.EventHandler для данных события и обработчика делегата события. Вторая процедура реализует событие с пользовательскими данными; она определяет пользовательские классы для данных события и обработчика делегата события.

Реализация событий без специальных данных

1) Определите общий элемент события в классе. Задайте тип элемента события делегату System.EventHandler.

public class Countdown

{ // ...

public event EventHandler CountdownCompleted;

}

2) Предоставьте защищенный метод в своем классе, который инициирует событие. Присвойте методу имя OnEventName. Создайте событие в методе.

public class Countdown

{

public event EventHandler CountdownCompleted;

protected virtual void OnCountdownCompleted(EventArgs e)

{

if (CountdownCompleted != null)

CountdownCompleted(this, e);

}

}

3) Определите, когда нужно создавать событие в классе. Вызовите OnEventName для создания события.

public class Countdown

{

int internalCounter = 0;

// ...

public event EventHandler CountdownCompleted;

protected virtual void OnCountdownCompleted(EventArgs e)

{

if (CountdownCompleted != null)

CountdownCompleted(this, e);

}

public void Decrement()

{

internalCounter--;

if (internalCounter == 0)

OnCountdownCompleted(new EventArgs());

}

}

Реализация события со специальными данными

1) Определите класс, который предоставляет данные для события. Задайте классу имя EventNameArgs, унаследуйте класс от System.EventArgs, и добавьте любые элементы, характерные для события.

public class AlarmEventArgs : EventArgs

{

private readonly int nRings = 0;

private readonly bool pressed = false;

private string text = "The alarm is ringing!";

// Constructor.

public AlarmEventArgs(bool snoozePressed, int nRings)

{

this.pressed = snoozePressed;

this.nRings = nRings;

}

// Properties.

public string AlarmText {

get { return text; }

set { this.text = value; }

}

public int NumRings {

get { return nRings; }

}

public bool SnoozePressed {

get { return pressed; }

}

}

2) Объявите делегата для события. Задайте делегату имя EventNameEventHandler.

public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);

3) Определите общий элемент события с именем EventName в классе. Задайте тип элемента события как тип делегата событий.

public class AlarmClock

{ // ...

public event AlarmEventHandler Alarm;

}

4) Определите защищенный метод в своем классе, который создает событие. Присвойте методу имя OnEventName. Создайте событие в методе.

public class AlarmClock

{ // ...

public event AlarmEventHandler Alarm;

protected virtual void OnAlarm(AlarmEventArgs e)

{

if (Alarm != null)

Alarm(this, e);

}

}

5) Определите, когда нужно создавать событие в классе. Вызовите метод OnEventName для порождения события и передайте характерные для события данные с помощью аргументов EventArgs события EventName.

public class AlarmClock

{

public void Start()

{

// ...

System.Threading.Thread.Sleep(300);

AlarmEventArgs e = new AlarmEventArgs(false, 0);

OnAlarm(e);

}

public event AlarmEventHandler Alarm;

protected virtual void OnAlarm(AlarmEventArgs e)

{

if (Alarm != null)

Alarm(this, e);

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]