代码之家  ›  专栏  ›  技术社区  ›  HaxElit

添加和删除匿名事件处理程序

  •  51
  • HaxElit  · 技术社区  · 16 年前

    我想知道这是否真的有效?

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

    编译器如何知道事件处理程序是相同的?这是推荐的吗?

    6 回复  |  直到 12 年前
        1
  •  63
  •   Ryan Lundy    16 年前

    How to Subscribe to and Unsubscribe from Events

    特别注意:

    如果您不必取消订阅[sic] 在以后的事件中,您可以使用 将匿名方法附加到

    而且:

    重要的是要注意你 函数来订阅它。到 取消订阅在这种情况下,它是 您订阅了活动,存储了 委托中的匿名方法 变量,然后将委托添加到 不要使用匿名 在以下情况下订阅事件的函数: 您将不得不取消订阅 事件将在以后的某个时间发生

        2
  •  20
  •   Sebastian Hübner sb.olofsson    7 年前

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

    更新: 在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;
    }
    
        3
  •  6
  •   Dan Herbert    16 年前

    如果需要取消订阅事件处理程序,则需要对具体委托有明确的引用。看着 Delegate.Equality 您将发现,代理不只是使用引用相等进行比较,但是这对于匿名代理并不重要。

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

        4
  •  3
  •   Noldorin    16 年前

    这恐怕行不通,因为您声明的两个lambda表达式(和委托)实际上是不同的对象,并且返回不同的引用。因此,删除处理程序( -= )永远都会失败。

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

        5
  •  2
  •   Dan Auclair    16 年前

    我认为这行不通。如果确实需要从事件中注销,则必须指定一个显式事件处理程序,以后可以从该处理程序而不是匿名委托中注销。

        6
  •  1
  •   Codism    16 年前

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

    推荐文章