添加和删除匿名事件处理程序
我想知道这是否真的有效?
private void RegisterKeyChanged(T item)
{
item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k);
}
private void UnRegisterKeyChanged(T item)
{
item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k);
}
编译器如何知道事件处理程序是相同的?这还推荐吗?
I was wondering if this actually worked ?
private void RegisterKeyChanged(T item)
{
item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k);
}
private void UnRegisterKeyChanged(T item)
{
item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k);
}
How does the compiler know that the event handlers are the same ? Is this even recommended?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
有一个 MSDN 页面讨论了这一点:
如何订阅和取消订阅事件
特别注意:
还有:
There's an MSDN page that talks about this:
How to Subscribe to and Unsubscribe from Events
Note in particular:
And also:
对于任何感兴趣的人,您可以添加和删除匿名事件处理程序,如下
更新:
在 C# 7.0 中,我们支持 本地函数,因此
TuneGuitar
方法现在可以编写为:For anyone interested, you can add and remove an anonymous event handler like this
UPDATE:
In C# 7.0 we have supports for local functions so the
TuneGuitar
method can now be written as:如果您需要取消订阅事件处理程序,则需要对具体委托有明确的引用。查看
Delegate.Equality
您会发现委托不仅仅是使用引用相等进行比较,但这对于匿名委托来说并不重要。对于匿名委托,编译器(基本上)只是为每个匿名委托创建一个新的“非匿名”委托,即使委托主体相同。因此,当您使用您提供的代码示例时,框架将找不到要取消订阅的委托。
If you need to unsubscribe an event handler, you'll need to have a definite reference to a concrete delegate. Looking at
Delegate.Equality
you will find that delegates aren't just compared using reference equality, however this doesn't matter for anonymous delegates.For an anonymous delegate, the compiler (basically) just creates a new "non-anonymous" delegate for each anonymous delegate, even if the delegate bodies are the same. Because of this, the framework will not find the delegate to unsubscribe when you use the code example you gave.
恐怕这行不通,因为您声明的两个 lambda 表达式(和委托)实际上是不同的对象,并且返回不同的引用。因此,删除处理程序 (
-=
) 总是会失败。此问题的常见解决方案(需要删除处理程序)就是将lambda 表达式重构为正确的方法。另一种方法是为事件处理程序委托维护一个类变量,并添加和删除它,尽管我个人不喜欢它。 (如果有的话,这比仅仅创建一个普通方法更麻烦。)
That won't work I'm afraid, since the two lambda expressions (and delegates) that you declared are actually different objects, and return different references. Hence, the removal of the handler (
-=
) will always fail.The common solution to this problem (where you need to remove the handler) is simply to refactor the lamba expression into a proper method. An alternative is to maintain a class variable for the event handler delegate, and add and remove this, though I am personally not a fan of it. (It's more hassle than just creating a normal method, if anything.)
我不相信这会起作用。如果您确实需要从事件中取消注册,则必须指定一个显式事件处理程序,您可以稍后从该事件处理程序中取消注册,而不是匿名委托。
I don't believe this will work. If you really need to unregister from an event you must specify an explicit event handler which you can later unregister from instead of an anonymous delegate.
如果您检查 Delegate.Equality 的文档,您会发现它们不是通过引用进行比较的。
If you check with the document for Delegate.Equality, you would find out they are not compared by reference.