Грег,
То, что у вас есть , не шаблон наблюдателя, а скорее очередь сообщений. Значит, вы просто используете неправильный шаблон проектирования для проблемы, которую пытаетесь решить.
Достаточно легко реализовать собственную очередь сообщений с нуля, используя Queue {Action {object}}
, где объекты ставятся в очередь сами, а вы просто удаляете их из очереди по мере их вызова.
Обычный способ - сохранить логическое значение, указывающее, должно ли оно выполняться ...
bool runMyEvent = true;
void Handler(object sender, EventArgs e) {
if (runMyEvent) {
// handler here
runMyEvent = false;
} else {
return;
}
}
Здесь вы можете использовать метод однократного запуска, упомянутый здесь несколько раз, но с этим есть несколько проблем, в зависимости от вашего варианта использования.
1) Возможно, вы захотите повторно -зацепите метод позже и снова запустите его. Хотя я полагаю, что вы можете сбросить свой bool
2) У вас все еще есть эта ссылка, которая может в конечном итоге сохранить ваш класс в памяти вместо того, чтобы собирать мусор.
Один из вариантов - использовать анонимный метод и закрытие, когда вы определяете обработка событий:
public class Foo
{
public EventHandler<EventArgs> MyEvent;
public void FireEvent()
{
if(MyEvent != null)
MyEvent(this, EventArgs.Empty);
}
}
Foo obj = new Foo();
Action<object, EventArgs> action = new Action<object, EventArgs>((sender, args) =>
{
// We're now running the event handler, so unsubscribe
obj.MyEvent -= new EventHandler<EventArgs>(action);
// Do whatever you wanted to do when the event fired.
});
obj.MyEvent += new EventHandler<EventArgs>(action);
как насчет обработчика, который запускается только один раз? Примерно так:
if (wasRun) return; wasRun = true;
Если это имеет смысл (и если у вас есть доступ к код, который вызывает обработчики), возможно, вы могли бы просто удалить все события после запуска обработчика .
Не знаю, хорошая ли это идея, просто еще одна мысль.
Вы можете использовать объекты WeakReference, чтобы представить, так сказать, слабых подписчиков . Во время запуска события вы можете проверить, была ли уже собрана слабая ссылка, и при необходимости удалить этого подписчика из списка подписчиков.
Основная идея заключается в том, что когда подписчики собираются GC, ваш обработчик заметит это и выбросит их вне списка подписчиков.
На CodeProject есть подробная статья: Слабые события , в которой рассматриваются несколько решений этой проблемы.
Я обычно делаю что-то вроде следующего, чтобы реализовать однократный обработчик событий.
void OnControlClickOneTime(this Control c, EventHandler e) {
EventHandler e2 = null;
e2 = (s,args) => {
c.Click -= e2;
e(s,args);
};
c.Click += e2;
}