Данная заметка — попытка вставить свои 5 копеек на тему, затронутую в статье пользователя KumoKairo.
Не далее как год назад я столкнулся с подобной проблемой — необходимо было рассылать события клиентам из WCF-службы, причем один подписчик события не должен страдать от того, что другой подписчик события в момент генерации этого события отвалился.
Как и автор упомянутой заметки, я пошел смотреть, что же такого умного написано на эту тему, и набрел вот на эту публикацию. Пришел к выводу, что строго говоря, задача не решается, то есть мы никак не сможем избежать случайного вызова обработчика событий от того подписчика, который отписался в «неудобный» момент. Но есть неплохой способ избежать последствий такой ситуации.
Примерный код приведен ниже (мое решение в продуктовом коде было несколько более корявым):
delegate void SomeEventHandler(object sender, EventArgs a);
class SampleHandlers
{
SomeEventHandler someEvent;
Dictionary<SomeEventHandler, SomeEventHandler> m_actions = new Dictionary<SomeEventHandler, SomeEventHandler>();
readonly object someEventLock = new object();
//Подписка/отписка от события
public event SomeEventHandler SomeEvent
{
add
{
lock (someEventLock)
{
SomeEventHandler h = new SomeEventHandler((o, a) =>
{
try { value(o,a); }
catch
{
//тут как-то это обрабатываем. Я или просто пишу в лог, или удаляю
//обработчик (что на самом деле непросто), - в зависимости от типа исключения.
}
});
someEvent += h;
m_actions[value] = h;
}
}
remove
{
lock (someEventLock)
{
try
{
SomeEventHandler h = m_actions[value];
m_actions.Remove(value);
someEvent -= h;
}
catch
{ /*тут как-то это обрабатываем, я тут просто пишу в лог*/}
}
}
}
//Генерация события:
protected virtual void OnSomeEvent(EventArgs e)
{
SomeEventHandler handler;
lock (someEventLock)
{
handler = someEvent;
}
if (handler != null)
{
handler(this, e);
}
}
}
Как видно, идея просто в том, чтобы вызов каждого клиентского обработчика «на всякий пожарный» обернуть в «свой» блок try-catch. Ну и для нормального «отписывания» пришлось немного нагородить — добавить словарь соответствия между клиентскими обработчиками и нашими. Мне кажется, описанный способ имеет право на существование. Если можно что-то похожее реализовать легче/правильнее, я буду рад ссылкам и комментариям.