Обработчик событий уже добавлен? - PullRequest
169 голосов
/ 26 сентября 2008

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

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

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

Возможно ли это?

РЕДАКТИРОВАТЬ: я не обязательно имею полный контроль над тем, какие обработчики событий добавляются, так что просто проверка на ноль не достаточно хороша.

Ответы [ 8 ]

177 голосов
/ 15 августа 2011

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

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

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

115 голосов
/ 26 сентября 2008

За пределами определяющего класса, как упоминает @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.

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

18 голосов
/ 26 сентября 2008

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

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

6 голосов
/ 26 сентября 2008

В этом примере показано, как использовать метод 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 делегата, чтобы увидеть, была ли добавлена ​​определенная функция.

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

4 голосов
/ 26 сентября 2008

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

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

0 голосов
/ 23 мая 2019

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

bool alreadyAdded = false;

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

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}
0 голосов
/ 23 марта 2016

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

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }
0 голосов
/ 26 сентября 2008
EventHandler.GetInvocationList().Length > 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...