通过匿名委托取消订阅事件

本文关键字:取消 事件 | 更新日期: 2023-09-27 18:19:50

我多次使用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);
}

我如何纠正或优化这件事

通过匿名委托取消订阅事件

您可以将lamdba提取到变量:

EventHandler func = (sender, e) =>
    listView_PreviewTextInput(sender, e, listView);
if (((bool)e.NewValue))
{
    listView.PreviewTextInput += func;
}
else
{
    listView.PreviewTextInput -= func;
}

警告!史蒂文接受的答案是错误的,它所做的只是掩盖一个重新打磨警告的问题。

每次执行给定代码时

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

您将获得一个新的(因为您可能捕获不同的listView)匿名委托实例,该实例保存到func,该实例尚未订阅任何事件,因此该代码为

listView.PreviewTextInput -= func;

将有效地什么都不做,因为你不能取消订阅你没有订阅的事件。这将导致令人难以置信的错误,如事件处理程序"调用两次",内存泄漏等。

事实上,Jon Skeet说它在某些情况下可能有效:

C#规范明确指出(IIRC),如果您有两个匿名函数(匿名方法或lambda表达式)或者不能从该代码创建相等的委托。

例如,当编译器不是每次都生成新的实例时,您将看到良好的行为。

但这是不可靠的,当然在启动器问题中描述的带有捕获变量listView的情况下也不起作用。

所以我的建议是:

只有在您永远不必取消订阅的情况下,才使用匿名函数作为事件处理程序