Был ли добавлен обработчик событий?

Есть ли способ узнать, добавлен ли обработчик событий к объекту? Я сериализую список объектов в / из состояния сеанса, чтобы мы могли использовать состояние сеанса на основе SQL ... Когда объект в списке имеет измененное свойство, его необходимо пометить, о чем обработчик событий позаботился должным образом перед . Однако теперь, когда объекты десериализованы, он не получает обработчик событий.

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

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

Это возможно?

Обновлено: я не обязательно полностью контролирую, какие обработчики событий добавляются, поэтому простой проверки на null недостаточно.

см. также stackoverflow.com/questions/367523/…

Ian Ringrose 30.12.2014 15:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
194
1
148 456
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Если это единственный обработчик, вы можете проверить, имеет ли событие значение null, если нет, обработчик добавлен.

Я думаю, вы можете безопасно вызвать - = для события с вашим обработчиком, даже если он не добавлен (если нет, вы можете его поймать), чтобы убедиться, что его нет, перед добавлением.

Эта логика сломается, как только событие будет обработано где-то еще.

bugged87 15.10.2015 20:44

EventHandler.GetInvocationList().Length > 0

разве это не бросает, когда список == null?

Boris Callens 16.06.2009 16:17

вне класса, владеющего обработчиком событий, вы можете использовать только - = и + =. вы не можете получить доступ к событию.

tbergelt 10.08.2011 07:13
Ответ принят как подходящий

За пределами определяющего класса, как упоминает @Telos, вы можете использовать EventHandler только с левой стороны += или -=. Итак, если у вас есть возможность изменить определяющий класс, вы можете предоставить метод для выполнения проверки, проверив, является ли обработчик событий null - если да, то обработчик событий не был добавлен. Если нет, то, возможно, и вы можете перебрать значения в Delegate.GetInvocationList. Если один равен делегату, которого вы хотите добавить в качестве обработчика событий, значит, вы знаете, что он есть.

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{   
    if ( this.EventHandler != null )
    {
        foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
        {
            if ( existingHandler == prospectiveHandler )
            {
                return true;
            }
        }
    }
    return false;
}

И это можно легко изменить, чтобы он стал «добавить обработчик, если его нет». Если у вас нет доступа к внутренностям класса, который раскрывает событие, вам может потребоваться изучить -= и +=, как предлагает @Lou Franco.

Однако вам может быть лучше пересмотреть способ ввода в эксплуатацию и вывода из эксплуатации этих объектов, чтобы увидеть, не сможете ли вы найти способ самостоятельно отслеживать эту информацию.

Это не компилируется, EventHandler может находиться только слева от + = или - =.

CodeRedick 26.09.2008 18:00

После дальнейших объяснений голосование "против" отменено. Состояние SQL в значительной степени разрушает всю идею здесь ... :(

CodeRedick 26.09.2008 22:25

Спасибо, Блэр и SO search, именно то, что я искал (раздражает, что вы не можете делать это вне класса)

George Mauer 19.12.2008 17:39

На самом деле, это ОТЛИЧНЫЙ ответ, который решил очень сложную ошибку в моем коде. Благодаря тонну!

andreapier 14.08.2013 18:37

Проблема возникает в большинстве случаев при сравнении делегатов на равенство. Поэтому используйте Delegate.Equals(objA, objB), если хотите проверить наличие точно такого же делегата. В противном случае сравните свойства по отдельности, как if (objA.Method.Name == objB.Method.Name && objA.Target.GetType().FullName == objB.Target.GetType().FullName).

Sanjay 06.08.2014 17:21

Этот код не работает в WinForm. Это строго для ASP.NET?

jp2code 22.05.2015 22:57

@Sanjay Вы правы и избавили меня от множества поисков, поскольку код Блэра выдает предупреждение о возможном сравнении ссылок.

Sierramike 29.12.2016 17:07

Вместо этого уродливого цикла лучше выглядел бы метод «Содержит». ((IList) EventHandler.GetInvocationList ()). Содержит (prospecti‌ veHandler)

Xtro 27.10.2017 17:53

public static bool IsRegistered (этот обработчик EventHandler, Delegate prospectiveHandler) => обработчик! = null && handler.GetInvocationList (). Any (existingHandler => existingHandler == prospectiveHandler);

Latency 10.07.2018 22:55

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

public class MyClass
{
  event Action MyEvent;
}

...

MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;

...

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method

Вы можете изучить различные свойства свойства Method делегата, чтобы узнать, добавлена ​​ли конкретная функция.

Если вы хотите узнать, прикреплен ли он только один, вы можете просто проверить значение null.

GetInvocationList () не является членом моего класса. Фактически, я не могу найти этот метод ни для одного объекта или обработчика, к которому у меня есть доступ ...

CodeRedick 26.09.2008 17:59

Я тоже пробовал это, по-видимому, вы можете получить доступ к такому событию только изнутри класса. Я делаю это в общем, и, как уже упоминали другие, обработчики событий, вероятно, все равно теряются. Благодарю за разъяснение!

CodeRedick 26.09.2008 22:27

Если я правильно понимаю вашу проблему, у вас могут быть проблемы посерьезнее. Вы сказали, что другие объекты могут подписаться на эти события. Когда объект сериализуется и десериализуется, другие объекты (те, над которыми вы не контролируете) потеряют свои обработчики событий.

Если вас это не беспокоит, то достаточно будет ссылки на обработчик событий. Если вас беспокоят побочные эффекты потери обработчиков событий другими объектами, возможно, вам стоит пересмотреть свою стратегию кэширования.

Ооо! Даже не подумал об этом ... хотя это должно было быть очевидным, учитывая мою первоначальную проблему, заключалась в том, что мой собственный обработчик терялся.

CodeRedick 26.09.2008 22:23

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

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;

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

Кажется рискованным; если событие запускается после удаления обработчика и до его повторного добавления, оно будет пропущено.

Jimmy 04.06.2012 20:13

Конечно. Вы имеете в виду, что это не потокобезопасный Но это может быть проблемой только при запуске нескольких потоков и т.п., что необычно. В большинстве случаев этого должно быть достаточно для простоты.

alf 05.06.2012 04:54

Я думаю, что это лучший способ сделать это, просто попробуйте каждый раз, когда вы добавляете его, все равно вычитаете, тогда вы можете быть в большей безопасности. иначе вы будете биться головой о стену, обнаружив, что тот же метод вызывается дважды

Mubashar 09.02.2013 10:05

Меня это беспокоит. Тот факт, что вы в настоящее время явно не создаете потоки в своем коде, не означает, что нет нескольких потоков или что они не будут добавлены позже. Как только вы (или кто-то другой в команде, возможно, через несколько месяцев) добавляете рабочий поток или отвечаете как на пользовательский интерфейс, так и на сетевое соединение, это открывает дверь для очень прерывистых сброшенных событий.

Technophile 15.08.2015 00:46

Я считаю, что временной интервал между удалением и повторным добавлением настолько мал, что вряд ли будут пропущенные события, но да, это все еще возможно.

Alisson 17.08.2017 17:25

Если вы используете это для чего-то вроде обновления пользовательского интерфейса и т. д., Тогда это такая тривиальная задача, риск в порядке. Если бы это было для обработки сетевых пакетов и т. д., Я бы не стал его использовать.

rolls 13.09.2017 04:49

@alf: В веб-приложении это не только обычно, но и в однопользовательском режиме.

Stefan Steiger 07.09.2018 16:58

Всегда можно синхронизировать. Приостановите запуск события до завершения удаления / добавления.

ed22 10.05.2019 16:21

Это не работает с некоторыми обработчиками событий, такими как: MediaPlayer.Changed -= Player_Changed; Выдает исключение Handler has not been registered with this event.

Nicke Manarin 12.11.2019 17:47

не работает с асинхронным режимом

Toolkit 08.12.2020 18:37

Я согласен с ответом Альфа, но небольшие изменения в нем есть, использовать,

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }

Единственный способ, который сработал для меня, - это создать логическую переменную, для которой я установил значение true при добавлении события. Затем я спрашиваю: если переменная ложна, я добавляю событие.

bool alreadyAdded = false;

Эта переменная может быть глобальной.

if (!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}

Другие вопросы по теме