logo
C#, 320 стр

Пример "Комбинирование делегатов"

Рассмотрим следующую ситуацию. Пусть есть городские службы: милиция, скорая помощь, пожарные. Каждая из служб по-своему реагируют на события, происходящие в городе. Построим примитивную модель жизни города, в которой случаются события и сообщения о них посылаются службам. В последующей лекции эта модель будет развита. Сейчас она носит формальный характер, демонстрируя, главным образом, работу с делегатами, заодно поясняя ситуации, в которых разумно комбинирование делегатов.

Начнем с построения класса с именем Combination, где, следуя уже описанной технологии, введем делегатов как закрытые свойства, доступ к которым идет через процедуру-свойство get. Три делегата одного класса будут описывать действия трех городских служб. Класс будет описываться ранее введенным делегатом MesToPers, размещенным в пространстве имен проекта. Вот программный код, в котором описаны функции, задающие действия служб:

class Combination

{

private static void policeman(string mes)

{

//анализ сообщения

if(mes =="Пожар!")

Console.WriteLine(mes + " Милиция ищет виновных!");

else

Console.WriteLine(mes +" Милиция здесь!");

}

private static void ambulanceman(string mes)

{

if(mes =="Пожар!")

Console.WriteLine(mes + " Скорая спасает пострадавших!");

else

Console.WriteLine(mes + " Скорая помощь здесь!");

}

private static void fireman(string mes)

{

if(mes =="Пожар!")

Console.WriteLine(mes + " Пожарные тушат пожар!");

else

Console.WriteLine( mes + " Пожарные здесь!");

}

}

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

public static MesToPers Policeman

{

get {return (new MesToPers(policeman));}

}

public static MesToPers Fireman

{

get {return (new MesToPers(fireman));}

}

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;

Comb("День города!");

Comb -= Combination.Ambulanceman;

Comb -= Combination.Fireman;

Comb("На следующий день!");

}//TestSomeServices

Обратите внимание, здесь демонстрируется вызов свойства Method, возвращающее объект, свойство Name которого выводится на печать. Результаты, порожденные работой этой процедуры, изображены на рис. 20.6.

Рис. 20.6.  Службы города