else· Console.WriteLine("Замена элемента запрещена." + · " Значение = {0}", value); · } · get {return(base[index]);} } Таким образом, обработчикам можно запретить изменение входных аргументов события. Но есть еще выходные аргументы события, значения которых определяются в обработчике; в нашем примере это аргумент Permit. И здесь возникает коллизия интересов - каждый обработчик по своему может формировать значения выходных аргументов, не обращая внимания на результаты работы предыдущих обработчиков. Преимуществом в таких ситуациях обладает последний работающий обработчик события. Эта проблема остается открытой, в языке C# здесь "дыра" - нет специальных средств, позволяющих избежать или, по крайней мере, предупредить о возникновении подобной ситуации. Вся ответственность лежит на программисте, который может выбрать некоторую стратегию решения проблемы, отдавая, например, предпочтение решению одного из обработчиков или вырабатывая итоговое решение, учитывающее все частные решения. Итак, если событие имеет аргументы, то все входные аргументы должны быть закрыты для обработчиков события. Если обработчиков несколько, то лучше или не использовать выходных аргументов, или аккуратно запрограммировать логику обработчиков, которая учитывает решения, полученные коллегами - ранее отработавшими обработчиками события. Как было сказано, каждое событие класса представляется полем этого класса. Если у класса много объявленных событий, а реально возникает лишь малая часть из них, то предпочтительнее динамический подход, когда память отводится только фактически возникшим событиям. Это несколько замедляет время выполнения, но экономит память. Решение зависит от того, что в данном контексте важнее - память или время. Для реализации динамического подхода в языке предусмотрена возможность задания пользовательских методов Add и Remove в момент объявления события. Это и есть другая форма объявления события, упоминавшаяся ранее. Вот ее примерный синтаксис: public event <Имя Делегата> <Имя события> { add {...} remove {...} } Оба метода должны быть реализованы, при этом для хранения делегатов используется некоторое хранилище. Именно так реализованы классы для большинства интерфейсных объектов, использующие хэш-таблицы для хранения делегатов. Давайте построим небольшой пример, демонстрирующий такой способ объявления и работы с событиями. Вначале построим класс с несколькими событиями: class ManyEvents { //хэш таблица для хранения делегатов Hashtable DStore = new Hashtable(); public event EventHandler Ev1 { add { DStore["Ev1"]= (EventHandler)DStore["Ev1"]+ value; } remove { DStore["Ev1"]= (EventHandler)DStore["Ev1"]- value; |