通过匿名代表取消订阅活动

时间:2012-01-10 12:10:25

标签: c# wpf attachedbehaviors

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

我怎样才能纠正或优化这件事

2 个答案:

答案 0 :(得分:30)

您可以将lambda提取到变量:

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

if (((bool)e.NewValue))
{
    listView.PreviewTextInput += func;
}
else
{
    listView.PreviewTextInput -= func;
}

答案 1 :(得分:12)

警告! 来自史蒂文的Accepted answer 错误,所有这一切只是掩盖了resharper警告的问题。

每次执行代码

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

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

listView.PreviewTextInput -= func;

将无效,因为您无法取消订阅您未订阅的活动。这将导致令人难以置信的错误,例如事件处理程序“被称为两次”,内存泄漏等。

实际上,Jon Skeet说may work in some cases

  

C#规范明确规定(IIRC)如果你有两个   它可以是匿名函数(匿名方法或lambda表达式)   或者可能不会从该代码创建平等的代理。

e.g。当编译器每次都没有生成新实例时,你会看到很好的行为。

但这不可靠,当然在使用捕获的变量listView的起始问题中描述的情况下也不会起作用。

所以我的建议是:

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