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

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

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

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

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

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

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

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

Ответ 4

В этом примере показано, как использовать метод 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.

Ответ 5

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

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

Ответ 6

EventHandler.GetInvocationList().Length > 0

Ответ 7

Я согласен с alf-ответом, но небольшая модификация к нему, для использования,

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

Ответ 8

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

bool alreadyAdded = false;

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

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