Интернет-журнал "Домашняя лаборатория", 2007 №9 - Журнал «Домашняя лаборатория»
Шрифт:
Интервал:
}
public static MesToPers Ambulanceman
(
get (return (new MesToPers(ambulanceman));}
}
Три статических открытых свойства — Policeman, Fireman, Ambulanceman — динамически создают экземпляры класса MesToPers, связанные с соответствующими закрытыми функциями класса.
Службы у нас есть, покажем, как с ними можно работать. С этой целью добавим в класс Testing, где проводятся различные эксперименты, следующую процедуру:
public void TestSomeServices()
{
MesToPers Comb;
Comb = (MesToPers)Delegate.Combine(Combination.Ambulanceman,
Combination.Policeman);
Comb = (MesToPers)Delegate.Combine(Comb,Combination.Fireman);
Comb("Пожар!");
Вначале объявляется без инициализации функциональная переменная Comb, которой в следующем операторе присваивается ссылка на экземпляр делегата, созданного методом Combine, чей список вызова содержит ссылки на экземпляры делегатов Ambulanceman и Policeman. Затем к списку вызовов экземпляра Comb присоединяется новый кандидат Fireman. При вызове делегата Comb ему передается сообщение "Пожар!". В результате вызова Comb поочередно запускаются все три экземпляра входящие в список, каждому из которых передается сообщение.
Давайте теперь начнем поочередно отключать делегатов, вызывая затем Comb с новыми сообщениями:
Comb = (MesToPers)Delegate.Remove (Comb,Combination.Policeman);
//Такое возможно: попытка отключить не существующий элемент
Comb = (MesToPers)Delegate.Remove (Comb,Combination.Policeman);
Comb ("Через 30 минут!");
Comb = (MesToPers)Delegate.Remove(Comb,Combination.Ambulanceman);
Comb("Через час! ");
Comb = (MesToPers)Delegate.Remove(Comb,Combination.Fireman);
//Comb("Через два часа!"); // Comb не определен
В этом фрагменте поочередно отключаются разные службы — милиция, скорая помощь, пожарные, и каждый раз вызывается Comb. После последнего отключения, когда список вызовов становится пустым, вызов Comb приводит к ошибке, потому оператор вызова закомментирован.
Покажем теперь, что ту же работу можно выполнить, используя не методы, а операции:
//операции + и -
Comb = Combination.Ambulanceman;
Console.WriteLine(Comb.Method.Name);
Comb+= Combination.Fireman;
Comb+= Combination.Policeman;
Соmb("День города!");
Comb — = Combination.Ambulanceman;
Comb — = Combination.Fireman;
Comb("На следующий день!");
}//TestSomeServices
Обратите внимание, здесь демонстрируется вызов свойства Method, возвращающее объект, свойство Name которого выводится на печать. Результаты, порожденные работой этой процедуры, изображены на рис. 20.6.
Рис. 20.6. Службы города
Пример "Плохая служба"
Как быть, если в списке вызовов есть "плохой" экземпляр, при вызове которого возникает ошибка, приводящая к выбрасыванию исключительной ситуации? Тогда стоящие за ним в очереди экземпляры не будут вызваны, хотя они вполне могли бы выполнить свою часть работы. В этом случае полезно использовать метод GetInvocationList и в цикле поочередно вызывать делегатов. Вызов делегата следует поместить в охраняемый блок, тогда при возникновении исключительной ситуации в обработчике ситуации можно получить и выдать пользователю всю информацию о нарушителе, а цикл продолжит выполнение очередных делегатов из списка вызова.
Добавим в класс Combination "плохого" кандидата, который пытается делить на ноль:
//метод, вызывающий исключительную ситуацию
public static void BadService(string mes)
{
int i =7, j=5, k=0;
Console.WriteLine("Bad Service: Zero Divide");
j = i / k;
}
Создадим процедуру, в которой в списке вызовов есть хорошие и плохие кандидаты. Эта процедура использует управление исключительными ситуациями, о которых подробнее будет рассказано в последующих лекциях.
public void TestBadJob()
{
MesToPers Comb;
Comb = (MesToPers)Delegate.Combine(Combination.Ambulanceman,
Combination.Policeman);
Comb = (MesToPers)Delegate.Combine(Comb,
new MesToPers(Combination.BadService));
Comb = (MesToPers)Delegate.Combine(Comb,Combination.Fireman);
foreach(MesToPers currentJob in Comb.GetinvocationList())
{
try
{
currentJob("Пожар!");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(currentJob.Method.Name);
}
}
}//BadJob
Поясню, как будет работать эта процедура при ее вызове. Вначале две службы нормально отработают, но при вызове третьей службы возникнет исключительная ситуация "деление на ноль". Универсальный обработчик Exception перехватит эту ситуацию и напечатает как свойство Message объекта е, так и имя метода, вызвавшего исключительную ситуацию, используя свойство Method объекта, вызвавшего ситуацию. После завершения работы блока обработчика ситуации выполнение программы продолжится, выполнится следующий шаг цикла, и служба пожарных благополучно выполнит свою работу. Вот результаты вывода:
Рис. 20.7. "Плохая служба"
Разговор о делегатах еще не закончен. Он будет продолжен в следующей лекции, в которой рассмотрим классы с событиями. События основываются на делегатах.
21. События
Классы с событиями. Общий взгляд. Класс Sender и классы Receivers. Класс Sender. Как объявляются события? Делегаты и события. Классы с событиями, допускаемые. Net Framework. Класс EventArgs и его потомки. Входные и выходные аргументы события. Класс Receiver. Обработчик события. Встраивание объекта Sender. Связывание обработчика с событием. Отключение обработчика. Взаимодействие объектов sender и receiver. События — поля или процедуры-свойства? Динамическое связывание событий с их обработчиками.
Классы с событиями
Каждый объект является экземпляром некоторого класса. Класс задает свойства и поведение своих экземпляров. Методы класса определяют поведение объектов, свойства — их состояние. Все объекты обладают одними и теми же методами и, следовательно, ведут себя одинаково. Можно полагать, что методы задают врожденное поведение объектов. Этого нельзя сказать о свойствах — значения свойств объектов различны, так что экземпляры одного класса находятся в разных состояниях. Объекты класса "человек" могут иметь разные свойства: один — высокий, другой — низкий, один — сильный, другой — умный. Но методы у них одни: есть и спать, ходить и бегать. Как сделать поведение объектов специфическим? Как добавить им поведение, характерное для данного объекта? Один из наиболее известных путей — это наследование. Можно создать класс-наследник, у которого, наряду с унаследованным родительским поведением, будут и собственные методы. Например, наследником класса "человек" может быть класс "человек_образованный", обладающий методами: читать и писать, считать и программировать.
Есть еще один механизм, позволяющий объектам вести себя по-разному в одних и тех же обстоятельствах. Это механизм событий, рассмотрением которого мы сейчас и займемся. Класс, помимо свойств и методов, может иметь события. Содержательно, событием является некоторое специальное состояние, в котором может оказаться объект класса. Так, для объектов класса "человек" событием может быть рождение или смерть, свадьба или развод. О событиях в мире программных объектов чаще всего говорят в связи с интерфейсными объектами, у которых события возникают по причине действий пользователя. Так, командная кнопка может быть нажата — событие Click, документ может быть закрыт — событие close, в список может
Поделиться книгой в соц сетях:
Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!