Купить
 
 
Жанр: Учеба

Си шарп: создание приложений для windows

страница №12

енять.
Для начала определим два главных класса: DBManager и DBConnection.
class DBConnection
{ ... )
class DBKanager
(
static DBConnection [] activeConnections;
public delegate void EnumConnectionsCaliback(
DBConnection connection);
public static void EnumConnections (
EnumConnectionsCaliback callback!
{
foreach (DBConnection connection in activeConnections)
{
callback(connection);
Метод EnumConnectionsCallback является делегатом, что определяется
ключевым словом delegate в начале сигнатуры метода. Как видите, этот
делегат возвращает void и принимает единственный аргумент - объект
DBConnection. Метод EnumConnections в соответствии с его определением
принимает единственный аргумент - метод EnumConnectionsCallback. Чтобы
вызвать метод DBManager.EnumConnections, нам нужно лишь передать ему
экземпляр делегата DBManager.EnumConnectionsCallback.
194 Раздел I I . Фундаментальные понятия
Для создания экземпляра делегата нужно применить new, передав
ему имя метода, имеющего ту же сигнатуру, что и у делегата. Вот
пример:
DBManager.EnumConnectionsCallback myCallback =
new DBManager.EnuraConnectionsCallback(ActiveConnectionsCallback);
DBManager. EnumConnections(myCallback);
Заметьте, что это можно скомбинировать в единый вызов:
DBManager.EnumConnections(new
DBManager.EnumConnectionsCallback(ActiveConnectionsCallback));
Вот и все, что касается базового синтаксиса делегатов. Теперь посмотрим
на законченный пример:
using System;
class DBConnection
{
public DBConnection(string name)
f
this.name = name;
}
protected string Name;
public string name
{
get
{
return this.Name;
}
set
{
this.Name = value;
class DBManager
{
static DBConnection[] activeConnections;
public void AddConnections()
\
activeConnections = new DBConnection[5];
for (int 1=0; i " 5; i++)
{
activeConnections [ i ] =
new DBConnection{"DBConnection " + (i+ 1));
public delegate void EnumConnectionsCallback(DBConnection connection)
public static void EnumConnections(EnumConnectionsCallback callback)
Делегаты и обработчики событий 195
foreach (DBConnection connection in activeConnections)
i
callback (connection);
class DelegatelApp
i
public static void ActiveConnectionsCallback(DBConnection connection)
t
Console. WriteLine ( "Callback: функция вызвана для (0)", connection.name)
}
public static void Main()
{
DBManager dbMgr = new DBManager ();
dbMgr.AddConnections ( );
DBMsnager.EnumConnectionsCallback myCallback = new
DBManager.EnumConneсtionsCallback ( ActiveConnectionsCallback);
DBManager.EnumConnecrions(myCallback);
}
После компиляции и запуска этого приложения мы получим такие
результаты:
Callback функция вызвана для DBConnection 1
Callback функция вызвана для DBConnection 2
Callback функция вызвана для DBConnection 3
Callback функция вызвана для DBConnection 4
Callback функция вызвана для DBConnection 5
ДЕЛЕГАТЫ КАК СТАТИЧЕСКИЕ ЧЛЕНЫ
Довольно неуклюжее решение создавать экземпляр делегата при каждом
его применении, но в С# можно определять метод, который используется
при создании делегата, как статический член класса. Ниже приведен
пример с применением такого подхода. Заметьте, что теперь делегат
определен как статический член класса myCallback и может
использоваться в методе Main, так что клиенту нет нужды создавать
экземпляр делегата:
using System;
class DBConnection
{
public DBConnection(string name)
196 Раздел I I . Фундаментальные понятия
t
this.name = name;
)
protected string Name;
public string name
{
get
{
return this.Name;
}
set
(
this.Name = value;
class DBManager
(
static DBConnection[] activeConnections;
public void AddConnections()
{
activeConnections = new DBConnection[51;
for (int i = 0; i " 5; i++)
{
activeConnections [il = new DBConnection("DBConnection " + (i + 1))
public delegate void EnumConnectionsCallback(DBConnection connection);
public static void EnumConnections(EnumConnectionsCallback callback)
{
foreach {DBConnection connection in activeConnections)
{
callback(connection);
class Delegate2App
public static DBManager.EnumConnectionsCallback rayCallback =
new DBManager.EnumConnectionsCallback(AcziveConnectionsCaliback);
public static void ActiveConnectionsCallback(DBConnection connection)
Делегаты и обработчики событий 197
Console.WriteLine("Callback функция вызвана для {0}", connection.name);
I

public static void Mainj)
{
DBManager dbMgr = new DBManager();
dbMgr.AddConnections() ;
DBManager.EnumConnections(myCallback) ;
Общим правилом именования делегатов является добавление слова
Callback к имени метода, принимающего делегат в качестве аргумента.

Можно поошибке использовать имя этого метода вместо имени делегата.
При этом компилятор уведомит, что вы указали метод там, где ожидается
класс. Получив такую ошибку, помните: проблема в том, что вы указали
метод вместо делегата.
В двух примерах, которые мы рассмотрели, делегаты создаются независимо
от того, будут ли они когда-либо использоваться. В рассмотренных
вариантах ничего плохого в этом нет, поскольку известно, что они
будут вызываться. Но в целом при определении делегатов важно решить,
когда их создавать. Скажем, может случиться, что создание делегатов
потребует немало времени и затрат. В таких случаях, когда вы знаете,
что клиент обычно не обращается к данному методу обратного вызова,
можно отложить создание делегата до момента, пока он действительно
не потребуется, заключив создание его экземпляра в оболочку свойства.
Это иллюстрирует следующий измененный класс DBManager, в котором
для создания экземпляра делегата используется неизменяемое свойство
(поскольку для него представлен только метод-получатель);
using System;
class DBConnection
{
public DBConnection(string name)
{
this.name = name;
protected string Name;
public string name
{
get
i
return this.Name;
198 Раздел I I . Фундаментальные понятия
this.Name = value;
class DBManager
f
static DBConnection[] activeConnections;
public void AddConnections()
I

activeConnections - new DBConnection[5];
for (int i = 0; i " 5; i++)
{
a c t i v e C o n n e c t i o n s [ i ] = new DBConnection ("DBConnection " t- (i i 1))

1


public delegate void EnumConnectionsCallback(DBConnection connection);
public static void EnumConnections(EnumConnectionsCallback callback)
foreach (DBConnection connection in activeConnections)
callback(connection);
}
}

1


class Delegate3App
public DBManager.EnumConnectionsCallback myCailback
get
return new DBManager.EnumConnectionsCallback(ActiveConnectionsCallback)
public static void ActiveConnectionsCallback(DBConnection connection)
Console .WriteLine ("Callback функция вызвана для " •(• connection . name) ;
}
public static void Mainf)
Delegate3App app = new Delegate3App();
Делегаты и обработчики событий 199
DBManager dbMgr = new DBManagerf);
dbMgr.AddConnections(];
DBManager.EnumConnections(app.myCallback)
СОСТАВНЫЕ ДЕЛЕГАТЫ
Объединение делегатов - создание одного делегата из нескольких -
одна из тех возможностей, которая поначалу не кажется такой уж полезной,
но если вы столкнетесь с такой потребностью, то будете признательны
команде разработчиков С# за то, что они это предусмотрели. Рассмотрим
некоторые примеры, когда объединение делегатов может быть полезно.
В первом примере мы имеем дистрибьготорскую систему и класс,
просматривающий все наименования товара на данном складе, вызывая
метод обратного вызова для каждого наименования, запасов которого
менее 50 единиц. В реальном дистрибьюторском приложении формула
должна учитывать не только наличные запасы, но также заказанные и
находящиеся "в пути". Но возьмем простой пример: если наличие на
складе менее 50 единиц, возникает исключение.
Фокус в том, что мы хотим разделить методы, которые вызываются,
если запасы ниже допустимых: нам нужно запротоколировать сам факт
и, кроме того, послать письмо по электронной почте менеджеру по закупкам.

Итак, составим делегат из нескольких других:
using System;
using System.Threading;
class Pare
{
public Part(string sku)
i
this.Sku = sku;
Random r = new Random(DateTime.Now.Millisecond);
double d - r.NextDoubleO * 100;
this.CnHand - (int)d;
protected string sku;
public string sku
i
get
200 Раздел II. Фундаментальные понятия
return this.Sku;
i
set
this.Sku -1 value;
protected int OnHand;
public int onhand
get
return this.OnHand;
set
this.OnHand = value;
}
i
)
class InventoryManager
protected const int MIN__ONHAND - 50;
public Part[] parts;
public InventoryManager()
parts - new Part[5];
foe (int i = 0; i " 5; H-+)
Part part = new Part("Товар " + (i i 1));
Thread.Sleep(lO);
parts[i] = part;
Console.WriteLine("Добавление товара '{О}1 в наличии = (I)1
part.sku, part.onhand);
public delegate void OutOfStockExceptionMethod(Part parr);
public void Processlnventory(OutOfStockExceptionMethod exception)
{
Console.WriteLine("\Инвентаризация товара...");
Делегаты и обработчики событий 201
foreach (Part part in parts)
i
if (part.onhand " MIN_ONHAND)
{
Console.WriteLine("{0}: имеется в наличии {1}, " +
"это меньше, чем необходимо ({2})",
part. sku, part.onhand, MINjONHAND) ;
exception(part);
class CorapositeDelegatelApp
public static void LogEvent(Part part)
Console.WriteLine ("^протоколирование события ... ") ;
)
public static void EmailPurchasingMgr(Part part)
Console. WriteLine ("^уведомление менеджера по e-mail...");
}
public static void Main()
InventoryManager mgr = new InventoryManager();
InventoryManager.OutOfStockExceptionMethod LogEventCallback =
new InventoryManager.OutOfStockExceptionMethod(LogEvent);
InventoryManager.OutOfSrockExceptionMethod EmailPurchasingMgrCailback -
new InventoryManager.OutOfStockExceptionMethod(EraailPurchasingMgr);
InventoryManager,OutOfSrockExceptionMethod OnHandExceptionEventsCallback
ErrailPurchasingMgrCallback -i- LogEventCallback;
mgr.Processlnventory(OnHandExceptionEventsCallback);
В результате выполнения мы увидим примерно такой результат:
Добавление товара 'Товар V в наличии - 0
Добавление товара 'Товар 2' в наличии = 36
202 Раздел I I . Фундаментальные понятия
Добавление товара 'Товар 3' в наличии = 29
Добавление товара 'Товар 4' в наличии = 12
Добавление товара 'Товар 5' в наличии = 48
Инвентаризация товара...

Товар 1: имеется в наличии 0, это меньше, чем необходимо (50)
уведомление менеджера по e-mail...
протоколирование события...
Товар 2: имеется в наличии 36, это меньше, чем необходимо (50)
уведомление менеджера по e-mail...
протоколирование события...
Товар 3: имеется в наличии 29, это меньше, чем необходимо (50)
уведомление менеджера по e-mail...
протоколирование события...
Товар 4: имеется в наличии 12, это меньше, чем необходимо (50)
уведомление менеджера по e-mail...
протоколирование события...
Товар 5: имеется в наличии 48, это меньше, чем необходимо (50)
уведомление менеджера по e-mail...
протоколирование события...
Давайте рассмотрим программу подробнее. Вначале объявляется класс
Part:
class Part
{
public Part(string sku)
{
this.Sku = sku;
Random r = new Random(DateTime.Now.Millisecond) ;
double d = r.WextDoubleO * 100;
this.OnHand = (int)d;
protected string Sku;
{...}
protected int OnHand;
Этот класс предназначен для хранения информации о количестве товара,
расположенного на складе, и наименовании товара. В конструкторе
класса передается наименование товара и устанавливается его количество.
Количество товара устанавливается при помощи генерации случайных
чисел. Класс Random генерирует в произвольный момент времени
произвольное число. Функция Random.NextDouble () возвращает значение
от 0 до 1. При записи этого значения в переменную d мы умножаем возДелегаты
и обработчики событий 203
вращаемое значение на 100. При этом мы получаем число в пределах от
0 до 100. Это сгенерированное произвольным образом значение устанавливается
свойству OnHand.
Класс имеет два свойства sku и onhand.
Далее следует описание класса InventoryManager:
class InventoryManager
{
protected const int MIN_ONHAND = 50;
public Part[] parts;
public InventoryManager()
{
parts = new Part[51;
for (mt i - 0; i " 5; i+i )
{
Part part *= new Part ("Товар " I- (i + 1) ) ;
Thread.Sleep(lO);
parts[i] ^ pare;
Console.WriteLine("Добавление товара ' {0 } ' в наличии = {1}",
part.sku, part.onhand);
public delegate void OutOfStockExceptionMethod(Part part);
public void Processlnventory(OutOfStockExceptionMethod exception)
{
Console.WriteLine("\nProcessing inventory...");
foreach (Part part in parts)
{
if (part.onhand " MIN_ONHAND)
{
Console.WriteLine("{0]: имеется в налички (1), " +
"это меньше, чем необходимо (f2})",
part.sku, part.onhand, MINJ3NHAND);
exception(part) ;
Константная переменная MIN_ONHAND означает критическое количество
товара. Значит, если количество товара на складе менее этого значения, то
необходимо предпринять дополнительные действия для решения возникшей
проблемы. В классе InventoryManager объявлен массив объектов Part:
public Partf] parts
204 Раздел I I . Фундаментальные понятия
Конструктор инициализирует этот массив значениями. Инициализация
производится строкой "Товар" + порядковый номер элемента в массиве.

В цикле инициализации также вызывается функция
T h r e a d . S l e e p ( 1 0 ) ;
которая заставляет программу приостановиться на 10 миллисекунд. Это
необходимо для того, чтобы значения, генерируемые функцией Random,
имели больший разброс.
Далее в классе Inventory Manager объявляется делегат OutOfStockExceptionMethod,
принимающий параметр типа Part.
public delegate void OutOfStockExcepcionMethod(Part part);
Функция Processlnventory производит инвентаризацию товара на складе
и в случае возникновения исключения вызывает делегат. Функция ProcessInventory
просматривает все имеющиеся на складе товары и делает анализ
количества каждого. Если количество какого-либо товара менее 50, то
вызывается метод exception. Метод exception является делегатом, который
передается функции Processlnventory вызывающим методом.
Класс самого приложения содержит объявление двух делегатов, объединенных
в один составной делегат.
class CompositeDelegatelApp
{
public static void LogEvent(Part part)
f
Console.WriteLine ("^протоколирование события. . . ") ;
public static void EmailPurchasingMgr(Part part)
Console.WriteLine ("^уведомление менеджера по e-mail . . . " ) ;
!
public static void Main(I
InventoryManager mgr = new InventoryManager();
InventoryManager.OutOfStockExceptionMethod LogEventCallback =
new InventoryManager.OutOfStockExceptionMethod(LogEvent);
InventoryManager.OutOfStockExceptionMethod EmailPurchasingMgrCallback =
new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);
InventoryManager.OutOfStockExceptionMethod OnHandExceptionEventsCallback
EmailPurchasingMgrCallback + LogEventCallback;
mgr.Processlnventory(OnHandExceptionEventsCallback);
Делегаты и обработчики событий 205
Первый делегат LogEvent предназначен для создания протокола. Второй
делегат выполняет функции отсылки письма менеджеру с уведомлением.

В функции Main создаются экземпляры делегатов с именами LogEventCallback
и EmailPurchasingMgrCallback. Затем создается экземпляр составного
делегата с именем OnHandExceptionEventsCallback, который инициализируется
сразу двумя простыми делегатами: EmailPurchasingMgrCallback+ LogEventCallback,

Таким образом, эта возможность языка позволяет динамически определять,
какие методы нужно включать в метод обратного вызова и объединять
их в составной делегат. Исполняющая среда распознает, что эти
методы нужно вызвать последовательно. Кроме того, вы можете убрать
любой делегат из составного оператором "минус".
Тот факт, что эти методы вызываются последовательно, заставляет
спросить: почему просто не связать методы в цепочку, чтобы каждый
метод вызывал последующий? В нашем примере, где у нас всего два
метода, которые вызываются всегда одновременно, это сделать можно.
Но усложним пример. Допустим, у нас несколько магазинов, расположенных
в разных местах, и каждый сам решает, какие методы вызывать. К
примеру, на территории одного магазина находится общий товарный
склад, и здесь нужно запротоколировать событие и сообщить менеджеру
о закупках, а в других магазинах - запротоколировать событие и сообщить
управляющему магазина.
Такое требование легко реализовать, динамически создавая составной
делегат на основе информации о конкретном местоположении магазина.
Без делегатов нам пришлось бы написать метод, который не только определял
бы, какие методы вызывать, но и отслеживал, какие методы уже
вызывались, а какие еще нужно вызвать. Смотрите, как делегаты упрощают
эту потенциально сложную операцию:
using System;
using System.Threading;
class Part
t
public Part(string sku)
(
this.Sku = sku;
Random r = new Random(DateTime-Now.Millisecond);
double d = r.NextDouble() * 100;
this.OnHand = (int)d;
projected string Sku;
public string sku
206 Раздел II. Фундаментальные понятия
get
{
return this.Sku;
}
set
{
this.Sku = value
protected int OnHand;
public int onhand
{
get
f
return this.OnHand;
}
set
{
this.OnHand = value
f
class InventoryManager
{
protected const int MIN_ONHAND = 50;
public Part [ ] parts;
public InventoryManager()
{
parts = new Part[5];
for (int i = 0; i " 5; i++)
{
Part part = new Part("Товар " + (i + 1));
Thread.Sleep (10) ;
parts [i] = part;
Console.WriteLine("Добавление товара '(0)' в наличии = (1}
part.sku, part.onhand);
I

J
public delegate void OutOfStockExceptionMethod(Part part);
Делегаты и обработчики событий 207
public void Processlnventory(OutOfStockExceptionMethod exception)
{
Console.WriteLine("\Иквйнтаризацня товара...");
foreach (Part part in parts)
{
if (part.onhand " MIN__ONHAND)
{
Console.WriteLine("(0j: имеется в наличии {1}, " +
"это меньше чем необходимо ({2))",
part.sku, part.onhand, MIN__ONHAND) ;
exception(part);
class CompositeDelegate2App
(
public static void LogEvent(Part part)
(
C o n s o l e . W r i t e L i n e ( " ^ п р о т о к о л и р о в а н и е события . . . ") ;
}
public static void EmailPurchasingMgr(Part part)
{
Console.WriteLine ("^уведомление менеджера магазина. .. ") ;
}
public static void EmailStoreMgr(Part part)
{
Console .WriteLine ("^уведомление менеджера по закупкам... " ) ;
}
public static void Main О
{
InventoryManager mgr = new InventoryManagerО;
InventoryManager.OutOfStockExceptionMethod[] exceptionMethods
= new InventoryManager.OutOfStockExceptionMethod[3];
exceptionMethods[0] = new
InventoryManager.OutOfStockExceptionMethod(LogEvent);
exceptionMethods[1] = new
InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr)
exceptionMethods[2] = new
InventoryManager.OutOfStockExceptionMethod(EmailStoreMgr);
208 Раздел I I . Фундаментальные понятия
int location = 2;
InventoryManager.OutOfStockExceptionMethod compositeDelegate;
if (location == 2)
{
compositePelegate = exceptionMethods[0] + exceptionMethods[I]
}
else
{
compositeDelegate = exceptionMethods[0] + exceptionMethods[2]
;
mgr.ProcessInventory(compositeDelegateI ;
Теперь при компиляции и выполнении этого приложения результаты
будут отличаться в зависимости от значения переменной location. Например,
если вы зададите значение переменной location = 2, то сообщения
будут приходить менеджеру магазина:
Добавление товара 'Товар Г в наличии = 81
Добавление товара 'Товар 2' в наличии = 17
Добавление товара 'Товар 3' в наличии = 53
Добавление товара 'Товар 4' в наличии ~ 36
Добавление товара 'Товар 5' в наличии = 72
Инвентаризация товара...

Товар 2: имеется в наличии 17, это меньше чем необходимо (50)
протоколирование события...
уведомление менеджера магазина...
Товар 4: имеется в наличии 36, это меньше чем необходимо (50)
протоколирование события...
уведомление менеджера магазина...
Если же вы зададите значение переменной равным 1, то сообщения
будут приходить менеджеру по закупкам:
Добавление товара 'Товар Г в наличии = 52
Добавление товара 'Товар 2' в наличии = 88
Добавление товара 'Товар 3' в наличии = 81
Добавление товара 'Товар 4' в наличии = 65
Добавление товара 'Товар 5' в наличии ~ 1
Инвентаризация товара...
Товар 5: имеется в наличии 1, это меньше чем необходимо (50)
протоколирование события...
уведомление менеджера по закупкам...
Делегаты и обработчики событий 209
ОПРЕДЕЛЕНИЕ СОБЫТИЙ С ПОМОЩЬЮ ДЕЛЕГАТОВ
Практически во всех Windows-приложениях требуется асинхронная
обработка событий. Некоторые из этих событий связаны с самой ОС,
например, когда Windows посылает сообщения в очередь сообщений приложения
при том или ином взаимодействии пользователя с приложением.
Другие больше связаны с предметной областью, например, когда
нужно распечатать счет при обновлении заказа.
Работа с событиями в С# соответствует модели "издатель - подписчик",
где класс публикует событие, которое он может инициировать, и
любые классы могут подписаться на это событие. При инициации события
исполняющая среда следит за тем, чтобы уведомить всех подписчиков
о возникновении события.
Метод, вызываемый при возникновении события, определяется делегатом.
Однако нужно помнить об ограничениях, которые налагаются на
делегаты, используемые для этих целей. Во-первых, нужно, чтобы такой
делегат принимал два аргумента. Во-вторых, эти аргументы всегда должны
представлять два объекта: тот, что инициировал событие (издатель),
и информационный объект события, который должен быть производным
от класса EventArgs .NET Framework.
Скажем, мы хотим отслеживать изменения объемов запасов. Мы создаем
класс Inventor/Manager, который будет всегда использоваться при
обновлении запасов. Этот класс должен публиковать события, возникающие
при всяком изменении запасов вследствие закупок, продаж и других
причин. Тогда любой класс, которому нужно отслеживать изменения,
должен подписаться на эти события. Вот как это делается на С# при
помощи делегатов и событий:
using System;
class InventoryChangeEventArgs: EventArgs
{
public InventoryChangeEventArgs(string sku, int change)
;
this.sku = sku;
this.change = change;
string sku;
public string Sku
{
get
i
return sku;
210 Раздел I I . Фундаментальные понятия
int change;
public int Change
f
get
I

return change;
class InventoryManager // издатель
{
public delegate void InventoryChangeEventHandler(
object source, InventoryChangeEventArgs e);
public event InventoryChangeEventHandler OnlnventoryChangeHandler;
public void Updatelnventory(string sku, int change)
{
if (0 == change)
return;
InventoryChangeEventArgs e = new InventoryChangeEventArgs(sku, change)
if (OnlnventoryChangeHandler != null)
OnlnventoryChangeHandler(this, e);
class InventoryWatcher // подписчик
public InventoryWatcher(InventoryManager inventoryManager)
this.inventoryManager = inventoryManager;
inventoryManager.OnlnventoryChangeHandler
+= new InventoryManager.InventoryChangeEventHandler(OnlnventoryChange)
void OnlnventoryChange(object source, InventoryChangeEventArgs e)
int change = e.Change;
Console.WriteLine("Количество товара ' (0} ' было (1} на {2) единиц",
e.Sku,
change " 0 ? "увеличено": "уменьшено",
Math.Abs(e.Change));
InventoryManager inventoryManager;
}
class EventslApp
Делегаты и обработчики событий 211
public static void Main()
{
InventoryManager inventoryManager = new InventoryManager();
InventoryWatcher inventoryWatch - new InventoryWatcher(inventoryManager) ;
inventoryManager.Updatelnventory("Кетчуп Балтимор", -7);
inventoryManager.Updatelnventory("Масло растительное", 5);
}
)
Первая строка кода - это делегат, вы можете узнать его по определению
сигнатуры метода. Как уже говорилось, все делегаты, используемые
с событиями, должны быть определены с двумя аргументами: объектиздатель
(в данном случае source) и информационный объект события
(производный от EventArgs). Во второй строке указано ключевое слово event,
член, имеющий тип указанного делегата, и метод (или методы), которые
будут вызываться при возникновении события.

Updatelnventory - последний метод класса InventoryManager-вызывается
при каждом изменении запасов. Как видите, он создает объект типа
InventoryChangeEventArgs, который передается всем подписчикам и описывает
возникшее событие.
Теперь рассмотрим еще две строки кода:
if (OnlnventoryChangeHandler != null]
OnlnventoryChangeHandler(this, e);
Условный оператор if проверяет, есть ли подписчики, связанные с методом
OnlnventoryChangeHandler. Если это так, т. е. OnlnventoryChangeHandler
не равен null, инициируется событие. Вот и все, что касается издателя.
Теперь рассмотрим код подписчика.
Подписчик в нашем случае представлен классом InventoryWatcher. Ему
нужно выполнять две простые задачи. Во-первых, он должен указать себя
как подписчик, создав новый экземпляр делегата типа InventoryManager.InventoryChangeEventHandler,
и добавить этот делегат к событию InventoryManager,
OnlnventoryChangeHandler, Обратите особое внимание на синтаксис: для
добавления себя к списку подписчиков он использует составной оператор
присваивания +-, чтобы не уничтожить предыдущих подписчиков.
inventoryManager.OnlnventoryChangeHandler +-
new InventoryManager.InventoryChangeEventHandler (OnlnventoryChange);
Единственный аргумент, указываемый здесь,- имя метода, который
вызывается при возникновении события.
Последняя задача, которую должен выполнить подписчик,- это реализовать
свой обработчик событий. В данном случае обработчик ошибок
InventoryWatcher.OnlnventoryChange выводит сообщение об изменении запасов
с указанием номера позиции.
И, наконец, в коде этого приложения при каждом вызове метода
InventoryManager.Updatelnventory создаются экземпляры классов InventoryManager
и InventoryWatcher и автоматически инициируется событие,
которое приводит к вызову метода InventoryWatcher.OnlnventoryChange.
212 Раздел I I . Фундаментальные понятия
17. ОСОБЫЕ ВОЗМОЖНОСТИ С#
И Visual Studio .NET
XML ДОКУМЕНТИРОВАНИЕ КОДА С#
С# имеет особые возможности при создании комментариев к исходному
коду. Такой возможностью является XML документирование вашего
С# кода. Если вы ознакомитесь с опциями компилятора С#, то заметите
наличие параметра "/doc". Используя его, вы можете получить из исходно

Список страниц

Закладка в соц.сетях

Купить

☏ Заказ рекламы: +380504468872

© Ассоциация электронных библиотек Украины

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