C# 添加和删除匿名事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2051357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding and Removing Anonymous Event Handler
提问by HaxElit
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?
编译器如何知道事件处理程序是相同的?这甚至推荐吗?
采纳答案by Ryan Lundy
There's an MSDN page that talks about this:
有一个 MSDN 页面讨论了这个:
How to Subscribe to and Unsubscribe from Events
Note in particular:
特别注意:
If you will not have to unsubscribe to [sic] an event later, you can use the addition assignment operator (+=) to attach an anonymous method to the event.
如果以后不必取消订阅 [原文如此] 事件,则可以使用加法赋值运算符 (+=) 将匿名方法附加到事件。
And also:
并且:
It is important to notice that you cannot easily unsubscribe from an event if you used an anonymous function to subscribe to it. To unsubscribe in this scenario, it is necessary to go back to the code where you subscribe to the event, store the anonymous method in a delegate variable, and then add the delegate to the event . In general, we recommend that you do not use anonymous functions to subscribe to events if you will have to unsubscribe from the event at some later point in your code.
请务必注意,如果您使用匿名函数订阅事件,则无法轻松取消订阅事件。要在这种情况下取消订阅,需要返回订阅事件的代码,将匿名方法存储在委托变量中,然后将委托添加到事件中。通常,如果您必须在稍后的代码中取消订阅事件,我们建议您不要使用匿名函数来订阅事件。
回答by Codism
If you check with the document for Delegate.Equality, you would find out they are not compared by reference.
如果您检查 Delegate.Equality 的文档,您会发现它们没有通过引用进行比较。
回答by Dan Auclair
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.
我不相信这会奏效。如果您确实需要从事件中取消注册,则必须指定一个显式的事件处理程序,您以后可以从中取消注册,而不是匿名委托。
回答by Noldorin
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.
恐怕这行不通,因为您声明的两个 lambda 表达式(和委托)实际上是不同的对象,并返回不同的引用。因此,移除处理程序 ( -=
) 将始终失败。
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.)
这个问题的常见解决方案(您需要删除处理程序)只是将 Lamba 表达式重构为适当的方法。另一种方法是为事件处理程序委托维护一个类变量,并添加和删除它,尽管我个人并不喜欢它。(如果有的话,这比创建普通方法更麻烦。)
回答by Dan Herbert
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.
如果您需要取消订阅事件处理程序,则需要对具体委托有明确的引用。看看Delegate.Equality
你会发现委托不仅仅使用引用相等进行比较,但这对匿名委托来说并不重要。
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.
对于匿名委托,编译器(基本上)只是为每个匿名委托创建一个新的“非匿名”委托,即使委托主体相同。因此,当您使用您提供的代码示例时,框架将找不到要取消订阅的委托。
回答by sb.olofsson
For anyone interested, you can add and remove an anonymous event handler like this
对于任何感兴趣的人,您可以添加和删除这样的匿名事件处理程序
public class Musician
{
public void TuneGuitar()
{
Metronome metronome = new Metronome();
EventHandler<EventArgs> handler = null;
handler = (sender, args) =>
{
// Tune guitar
// ...
// Unsubscribe from tick event when guitar sound is perfect
metronome.Tick -= handler;
};
// Attach event handler
metronome.Tick += handler;
}
}
public class Metronome
{
event EventHandler<EventArgs> Tick;
}
UPDATE:
In C# 7.0 we have supports for local functionsso the TuneGuitar
method can now be written as:
更新:在 C# 7.0 中,我们支持本地函数,因此该TuneGuitar
方法现在可以编写为:
public void TuneGuitar()
{
Metronome metronome = new Metronome();
void handler(object sender, EventArgs args)
{
// Tune guitar
// ...
// Unsubscribe from tick event when guitar sound is perfect
metronome.Tick -= handler;
};
// Attach event handler
metronome.Tick += handler;
}