取消订阅处理程序内的事件是否总是安全的?

时间:2015-10-05 14:46:33

标签: c# events

让我们说我有这个(不完整的)类,我在其中引发一个事件而没有先将它分配给变量以使其成为线程安全的:

public class Test
{
    public event EventHandler SomeEvent;

    void OnSomeEvent(EventArgs e)
    {
        if (SomeEvent != null)
            SomeEvent(this, e);
    }
}

从自身取消订阅事件处理程序是否安全,或者是否存在类似于在枚举时从集合中删除项目时会发生什么问题?

void SomeEventHandler(object sender, EventArgs e)
{
    testInstance.SomeEvent -= SomeEventHandler;
}

2 个答案:

答案 0 :(得分:5)

稍微澄清另一个答案:

事件基于代表(几乎在所有情况下)。代表是不可改变的。这也适用于多播代理。

调用事件时,会加载委托,然后再调用委托。如果修改了代理所存储的字段,则不会影响已加载的代理。

因此,从处理程序修改事件是安全的。这些更改不会影响当前正在运行的调用。这是有保证的。

所有这些仅适用于委托支持的事件。 C#和CLR支持可以执行任何操作的自定义事件。

答案 1 :(得分:4)

然而,这是安全的,只是知道它不能保证SomeEventHandler中的代码只执行一次。如果您有多线程代码,则可能会出现争用情况。

修改: 取消订阅活动将在幕后组合代表以生成代表列表。 (很多细节可以在that article by Jon Skeet the man himself

找到

请注意,该事件使用锁来保证Delegate组合的线程安全性。将委托合并到您的活动后,您将获得一份委托的结果列表。但是,在举办活动时,保证的是将使用最新版本的合并代表。 (参见线程安全事件),但这与事件从事件内部取消挂钩的事实无关。

我希望我的编辑提供足够的说明:)