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

Hax*_*lit 54 c# events anonymous-methods

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

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);
}
Run Code Online (Sandbox Code Playgroud)

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

Rya*_*ndy 60

有一个MSDN页面讨论这个:

如何订阅和取消订阅活动

特别注意:

如果您以后不必取消订阅[sic]事件,则可以使用添加赋值运算符(+ =)将匿名方法附加到事件中.

并且:

重要的是要注意,如果您使用匿名函数订阅它,则无法轻松取消订阅事件.要在此方案中取消订阅,必须返回订阅事件的代码,将匿名方法存储在委托变量中,然后将委托添加到事件中.通常,如果您必须在代码中的某个稍后时间点取消订阅该事件,我们建议您不要使用匿名函数来订阅事件.


sb.*_*son 14

对于任何感兴趣的人,您可以添加和删除这样的匿名事件处理程序

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;
}
Run Code Online (Sandbox Code Playgroud)

更新:在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;
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ert 6

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

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