19

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

我该如何纠正或优化这件事

4

2 回答 2

33

您可以将 lamdba 提取到变量中:

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

if (((bool)e.NewValue))
{
    listView.PreviewTextInput += func;
}
else
{
    listView.PreviewTextInput -= func;
}
于 2012-01-10T12:14:36.313 回答
18

警告! Steven接受的回答错误的,它所做的只是掩盖了 resharper 警告的问题。

每次执行给定的代码

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

你会得到一个新的(因为你可能会捕获不同listView的)匿名委托实例保存到func,一个尚未订阅任何事件的实例,所以反过来这个代码

listView.PreviewTextInput -= func;

将实际上什么都不做,因为您无法取消订阅您未订阅的事件。这将导致令人难以置信的错误,例如事件处理程序“调用两次”、内存泄漏等。

实际上,Jon Skeet 说它在某些情况下可能会起作用

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

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

但这不可靠,并且在启动问题中使用捕获变量描述的情况下肯定行不通listView

所以我的建议是:

仅当您永远不必取消订阅时,才使用匿名函数作为事件处理程序。

于 2016-12-17T13:30:51.397 回答