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

发布于 2024-08-18 07:50:32 字数 295 浏览 6 评论 0原文

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

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

岁月流歌 2024-08-25 07:50:32

有一个 MSDN 页面讨论了这一点:

如何订阅和取消订阅事件

特别注意:

如果您不必取消订阅[原文如此]
稍后的事件,您可以使用
加法赋值运算符 (+=) 到
附加一个匿名方法
事件。

还有:

重要的是要注意,您
无法轻易取消订阅
如果您使用匿名,则发生事件
功能来订阅它。到
在这种情况下取​​消订阅,就是
需要回到代码所在的位置
您订阅该事件,存储
委托中的匿名方法
变量,然后将委托添加到
事件。一般来说,我们建议
您不使用匿名
订阅事件的函数,如果
您必须取消订阅
稍后某个时间点发生的事件
代码。

There's an MSDN page that talks about this:

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.

过潦 2024-08-25 07:50:32

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

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 中,我们支持 本地函数,因此 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;
}

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 functions so the TuneGuitar method can now be written as:

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;
}
醉生梦死 2024-08-25 07:50:32

如果您需要取消订阅事件处理程序,则需要对具体委托有明确的引用。查看 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.

沧笙踏歌 2024-08-25 07:50:32

恐怕这行不通,因为您声明的两个 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.)

深白境迁sunset 2024-08-25 07:50:32

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

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.

誰ツ都不明白 2024-08-25 07:50:32

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

If you check with the document for Delegate.Equality, you would find out they are not compared by reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文