V3084. Anonymous function is used to unsubscribe from event. No handlers will be unsubscribed, as a separate delegate instance is created for each anonymous function declaration.
Анализатор обнаружил потенциально ошибочную отписку от события с использованием анонимных функций.
Приведём пример некорректного кода:
public event EventHandler MyEvent;
void Subscribe()
{
MyEvent += (sender, e) => HandleMyEvent(e);
}
void UnSubscribe()
{
MyEvent -= (sender, e) => HandleMyEvent(e);
}
В приведённом примере объявлены методы 'Subscribe' и 'UnSubscribe' для, соответственно, подписки и отписки от события 'MyEvent'. В качестве обработчика события используется лямбда выражение. Подписка на событие в методе 'Subscribe' будет успешно выполнена - обработчик (анонимная функция) будет добавлен в событие.
Однако, метод 'UnSubscribe' не выполнит отписку ранее назначенного в методе 'Subscribe' обработчика. После выполнения данного метода, событие 'MyEvent' по-прежнему будет содержать обработчик, назначенный в 'Subscribe'.
Такое поведение обусловлено тем, что каждое объявление анонимной функции приводит к созданию отдельного экземпляра делегата, в нашем случае, с типом EventHandler. Таким образом, в методе 'Subscribe' была произведена подписка 'делегата 1', а в методе Unsubscribe производится отписка уже для 'делегата 2', несмотря на то, что тела данных делегатов идентичны. Так как наше событие на момент отписки содержит только 'делегат 1', отписка от 'делегата 2' никак не изменит значения 'MyEvent'.
Для того, чтобы корректно использовать анонимные функции при подписке на события (если потребуется дальнейшая отписка), можно сохранять обработчик-лямбду в отдельную переменную, и использовать её как при подписке, так и при отписке от события:
public event EventHandler MyEvent;
EventHandler _handler;
void Subscribe()
{
_handler = (sender, e) => HandleMyEvent(sender, e);
MyEvent += _handler;
}
void UnSubscribe()
{
MyEvent -= _handler;
}