Отмена подписки на мероприятие через анонимного делегата

Я много раз использую анализ кода Resharper 5.1 и получаю комментарий от resharper как

«Отмена подписки на мероприятие через анонимного делегата»

#Part of Code  

if (((bool)e.NewValue))
{
    listView.PreviewTextInput += (o,args) =>
        listView_PreviewTextInput(o,args,listView);
}
else
{
    listView.PreviewTextInput -= (o, args) => 
        listView_PreviewTextInput(o, args, listView);
}

Как я могу исправить или оптимизировать эту штуку


person Ankesh    schedule 10.01.2012    source источник


Ответы (2)


Вы можете извлечь lamdba в переменную:

EventHandler func = (sender, e) =>
    listView_PreviewTextInput(sender, e, listView);

if (((bool)e.NewValue))
{
    listView.PreviewTextInput += func;
}
else
{
    listView.PreviewTextInput -= func;
}
person Steven    schedule 10.01.2012
comment
Спасибо, но EventHandler должен быть конкретным, верно ?? Потому что это дает мне ошибку ... System.EvenTArgs is not assignable to TextCompositonEventArgs - person Ankesh; 10.01.2012
comment
В этом случае listView.PreviewTextInput не EventHandler, но, вероятно, EventHandler<TextCompositonEventArgs>, но я не могу знать, поскольку вы не указали это в своем вопросе. - person Steven; 10.01.2012
comment
Ага .. мой плохой .. Спасибо ни в коем случае ... :) - person Ankesh; 10.01.2012

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

Каждый раз, когда данный код выполняется

 EventHandler func = (sender, e) =>
     listView_PreviewTextInput(sender, e, listView);

вы получите свежий (поскольку вы можете захватывать разные listView) экземпляр анонимного делегата, сохраненный в func, экземпляр, который еще не подписан на какие-либо события, поэтому, в свою очередь, этот код

listView.PreviewTextInput -= func;

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

На самом деле, Джон Скит говорит, что может работать в некоторых случаях:

В спецификации C # явно указано (IIRC), что если у вас есть две анонимные функции (анонимные методы или лямбда-выражения), она может или не может создавать равные делегаты из этого кода.

например когда компилятор не генерирует каждый раз новый экземпляр, вы увидите приятное поведение.

Но это ненадежно и, конечно, не сработает в случае, описанном в начальном вопросе с захваченной переменной listView.

Итак, мое предложение:

Используйте анонимные функции в качестве обработчиков событий ТОЛЬКО в том случае, если вам никогда не придется отказываться от подписки.

person Shorstok    schedule 17.12.2016