通过匿名委托取消订阅事件[重复]
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 将匿名委托转为“普通”方法或本地函数以上是关于通过匿名委托取消订阅事件[重复]的主要内容,如果未能解决你的问题,请参考以下文章