通过匿名委托取消订阅事件[重复]

Posted

技术标签:

【中文标题】通过匿名委托取消订阅事件[重复]【英文标题】:Event unsubscription via anonymous delegate [duplicate] 【发布时间】:2012-02-06 20:27:14 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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

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

if (((bool)e.NewValue))

    listView.PreviewTextInput += func;

else

    listView.PreviewTextInput -= func;

【讨论】:

谢谢,但EventHandler 应该是具体的吧??因为它给了我一个错误...System.EvenTArgs is not assignable to TextCompositonEventArgs 在这种情况下,listView.PreviewTextInput 不是EventHandler,但可能是EventHandler<TextCompositonEventArgs>,但我无法知道,因为您没有在问题中表明这一点。跨度> 是的..我的错..谢谢新的方式... :)【参考方案2】:

警告! 来自 Steven 的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 表达式)可能 或者可能不会从该代码创建相等的委托。

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

但这是不可靠的,并且在入门问题中描述的带有捕获变量listView 的情况下肯定行不通。

所以我的建议是:

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

【讨论】:

那么正确的做法是什么? @Daanvl 将匿名委托转为“普通”方法或本地函数

以上是关于通过匿名委托取消订阅事件[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何取消注册“匿名”事件处理程序 [重复]

C#事件订阅和取消订阅重复项

删除匿名事件处理程序 [重复]

Angular HttpClient取消订阅[重复]

我需要手动取消订阅吗? - Angular 8 [重复]

C#里事件和委托有啥区别啊??