2010-01-12 84 views
46

我想知道这是否真的有效?添加和删除匿名事件处理程序

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); 
} 

编译器如何知道事件处理程序是一样的吗?这甚至推荐?

+0

[在C#中取消订阅匿名方法]的可能副本(https://stackoverflow.com/questions/183367/unsubscribe-anonymous-method-in-c-sharp) – 2017-09-26 14:05:25

回答

55

有大约这个会谈的MSDN页:

How to Subscribe to and Unsubscribe from Events

请特别注意:

如果你将不必退订[原文] 事件后,你可以使用 附加赋值运算符(+ =)至 将匿名方法附加到 事件。

而且也:

注意到你 不能轻易从 事件退订,如果你使用匿名 功能订阅它是非常重要的。在这种情况下 退订,它是 要回去的地方, 您订阅的情况下,存储 匿名方法的委托 变量,然后委托添加到 事件的代码。一般来说,我们建议您使用 ,您不使用匿名 函数订阅事件,如果 您将不得不在 代码的稍后时间取消订阅 事件。

+0

那么这是不是意味着,基本上OP中的内容不能像预期的那样工作?这是否意味着匿名代理,如果没有存储在订阅点,几乎不可能取消订阅? – 2013-09-10 11:41:58

+0

显然,是的。 – 2013-11-09 05:12:08

1

如果您检查Delegate.Equality的文档,您会发现它们没有通过引用进行比较。

3

我不相信这会起作用。如果您确实需要从事件注销,则必须指定一个显式事件处理程序,您可以稍后取消注册,而不是匿名代理。

2

这是行不通的恐怕,因为你声明的两个lambda表达式(和委托)实际上是不同的对象,并返回不同的引用。因此,移除处理程序(-=)将始终失败。

这个问题的常见解决方案(您需要删除处理程序)只是将lamba表达式重构为适当的方法。另一种方法是为事件处理程序委托维护一个类变量,然后添加并删除它,尽管我个人不是它的粉丝。 (比创建常规方法更麻烦,如果有的话)

+0

请注意,在中有一个非常相似的问题和答案,其中Reed Copsey提出了与我一样的解决方案。 – Noldorin 2010-01-12 18:39:34

5

如果您需要取消订阅事件处理程序,则需要对具体的代理进行明确的引用。看看Delegate.Equality你会发现代表不仅仅是使用引用相等进行比较,然而这对匿名代表来说并不重要。

对于匿名委托,编译器(基本上)只是为每个匿名委托创建一个新的“非匿名”委托,即使委托体是相同的。因此,当您使用您提供的代码示例时,框架不会找到委托来取消订阅。

8

任何有兴趣,你可以添加和删除一个匿名事件处理这样

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: 在C#7.0,我们有支持local functions所以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; 
}