Две проблемы с обработчиками событий — КиберПедия 

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...

Две проблемы с обработчиками событий

2021-04-18 130
Две проблемы с обработчиками событий 0.00 из 5.00 0 оценок
Заказать работу

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

Игнорирование коллег

Задумывались ли Вы, какую роль играет ключевое слово event, появляющееся при объявлении события? Событие, объявленное в классе, представляет экземпляр делегата. В предыдущей лекции, когда речь шла о делегатах, их экземпляры объявлялись без всяких дополнительных ключевых слов.

Слово «event» играет важную роль, позволяя решить проблему, названную нами «игнорированием коллег». В чем ее суть. Дело в том, что некоторые из классов receiver могут вести себя некорректно по отношению к своим коллегам, занимающимся обработкой того же события. При присоединении обработчика события в классе receiver можно попытаться вместо присоединения обработчика выполнить операцию присваивания, игнорируя, тем самым, уже присоединенный список обработчиков. Взгляните еще раз на процедуру OnConnect класса Receiver2; там демонстрируется такая попытка в закомментированном операторе. Аналогично, в процедуре OffConnect вместо отсоединения (операции –) можно попытаться присвоить событию значение null, отсоединяя тем самым всех других обработчиков.

С этим как-то нужно бороться. Ключевое слово «event» дает указание компилятору создать для события закрытое поле, доступ к которому можно получить только через два автоматически создаваемых для события метода: Add, выполняющий операцию присоединения «+=», Remove, выполняющий обратную операцию отсоединения «-=». Никаких других операций над событиями выполнять нельзя. Тем самым, к счастью, решается проблема игнорирования коллег. Ошибки некорректного поведения класса receiver ловятся еще на этапе трансляции.

Переопределение значений аргументов события

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

Приведенный выше пример «Работа со списками» демонстрирует не самый лучший способ определения аргументов, провоцирующий классы receiver на некорректное обращение с аргументами. Напомню, в классе ChangedEventArgs, определяющем аргументы события, оба свойства item и permit являются закрытыми. Но определены процедуры – свойства Item и Permit, реализующие полный доступ к свойствам, поскольку определены обе процедуры get и set. Это несколько облегчило задачу, поскольку позволило изменять значение входного аргумента item перед зажиганием события для передачи его обработчику события. Но входной аргумент оказался не защищенным, и обработчик события может не только использовать это значение для анализа, но и изменить его в качестве побочного эффекта своей работы. В этом случае другой обработчик события будет уже работать с некорректным значением. Что еще хуже, это измененное значение может использовать и класс, в процессе своей дальнейшей работы. Поэтому входные аргументы события должны быть закрытыми для обработчиков событий. Это нетрудно сделать и я приведу необходимые уточнения:

· В классе ChangedEventArgs следует изменить процедуру-свойство Item, удалив процедуру set, разрешающую изменение свойства. В качестве компенсации в класс следует добавить конструктор с аргументом, что позволит в классе, создающем событие, создавать объект класса ChangedEventArgs с нужным значением свойства item. Приведу соответствующий код:

public object Item

{

   get {return(item);}

   //set { item = value;}

}

public ChangedEventArgs(object item)

{

   this.item = item;

}

· В методы класса ListWithChangedEvent, зажигающие события нужно ввести изменения. Теперь перед каждым вызовом нужно создавать новый объект, задающий аргументы. Вот измененный код:

public override int Add(object value)

{

   int i=0;

   ChangedEventArgs evargs = new ChangedEventArgs(value);

   //evargs.Item = value;

   OnChanged(evargs);

   if (evargs.Permit)

      i = base.Add(value);

   else

      Console.WriteLine("Добавление элемента запрещено." +

      "Значение = {0}", value);

   return i;

}

 

public override void Clear()

{

   ChangedEventArgs evargs = new ChangedEventArgs(0);

   //evargs.Item=0;       

   OnChanged(evargs);

   base.Clear();

}

public override object this[int index]

{

   set

   {

      ChangedEventArgs evargs = new ChangedEventArgs(value);

      //evargs.Item = value;

      OnChanged(evargs);

      if (evargs.Permit)

        base[index] = value;

      else

        Console.WriteLine("Замена элемента запрещена." +

           " Значение = {0}", value);

   }

   get {return(base[index]);}

}

Таким образом, обработчикам событий можно запретить изменение входных аргументов события. Но есть еще выходные аргументы события, значения которых определяются в обработчике события; в нашем примере это аргумент Permit. И здесь возникает коллизия интересов, – каждый обработчик по-своему может формировать значения выходных аргументов, не обращая внимания на результаты работы предыдущих обработчиков. Преимуществом в таких ситуациях обладает последний работающий обработчик события.

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

Итак, если событие имеет аргументы, то все входные аргументы должны быть закрыты для обработчиков события. Если обработчиков несколько, то лучше не использовать выходных аргументов, или аккуратно запрограммировать логику обработчиков, учитывающую решения, полученные коллегами – ранее отработавшими обработчиками события.


Поделиться с друзьями:

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

Таксономические единицы (категории) растений: Каждая система классификации состоит из определённых соподчиненных друг другу...

Историки об Елизавете Петровне: Елизавета попала между двумя встречными культурными течениями, воспитывалась среди новых европейских веяний и преданий...

Архитектура электронного правительства: Единая архитектура – это методологический подход при создании системы управления государства, который строится...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.011 с.