通过匿名委托取消订阅事件
本文关键字:取消 事件 | 更新日期: 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
的情况下也不起作用。
所以我的建议是:
只有在您永远不必取消订阅的情况下,才使用匿名函数作为事件处理程序