【问题标题】:Are event subscribers called in order of subscription?事件订阅者是否按订阅顺序调用?
【发布时间】:2008-12-17 12:29:10
【问题描述】:

假设事件订阅者按订阅顺序调用是否安全?
示例:

void One(object sender, EventArgs e) {}
void Two(object sender, EventArgs e) {}

event EventHandler foo;

foo += One;
foo += Two;

触发事件时是否总是在 Two() 之前调用 One()?

编辑:
你当然不应该依赖它,我只是在想。这个想法是,多播委托类似于命令模式。所以我只是想知道。通常,您会使用一个保持命令顺序的集合,以便您可以执行撤消/重做/任何操作。

【问题讨论】:

标签: c# .net events .net-2.0 c#-2.0


【解决方案1】:

鉴于该实现,是的,它们将始终按该顺序调用。

如果事件实际上使用了一些奇怪而美妙的方式来处理订阅,它可以做不同的事情 - 但“正常”的实现会做正确的事情。

明确地说,订阅事件处理程序只是意味着调用事件的适当“添加”部分。如果事件通过执行以下操作来处理此问题:

myHandler += value;

被翻译成

myHandler = Delegate.Combine(myHandler, value);

和Delegate.Combine 保证订购。但是,如果您有这样的活动:

private LinkedList<EventHandler> eventHandlers = new LinkedList<EventHandler>;

public event EventHandler Foo
{
    add
    {
        eventHandlers.AddFirst(value);
    }
    remove
    {
        // do stuff here too
    }
}

然后通过执行以下操作触发事件:

foreach (EventHandler handler in eventHandlers)
{
    handler(this, EventArgs.Empty);
}

那么处理程序将以相反的顺序被调用。

总结:对于所有正常的事件,您可以依赖排序。理论上,事件可以为所欲为,但我从未见过不保持适当顺序的事件。

【讨论】:

  • 乔恩,你比大多数人都清楚,永远不应该依赖事件处理程序的执行顺序;你为什么要放这张幻灯片?
【解决方案2】:

请密切注意 Jon Skeet 给出的警告 - “鉴于该实施......”。换句话说,只要进行最轻微的更改(多线程、其他处理程序等),您就有可能失去执行顺序不变性。

不要不依赖事件排序。所有事件分派在逻辑上应该是独立的,就好像它们是并行发生的一样。事件是逻辑上独立的动作。

我会更进一步,并断言如果您必须承担事件触发的顺序,那么您存在严重的设计缺陷和/或滥用事件。

【讨论】:

    【解决方案3】:

    即使以正确的顺序调用它们,我也会尽量不编写依赖于先前已被触发的委托才能正常运行的代码。

    如果 Two() 依赖于 One() 正在执行的操作,则要么附加一个以正确顺序调用这两个方法的委托,要么让 Two() 在必要时调用 One()。

    【讨论】:

    • 此外,我想说没有这样一种正确的方式来通知订阅者。
    【解决方案4】:

    快速回答是“不关你的事”:)

    事件本质上是异步的。这意味着您不是在等待事件被触发或期望它在给定时间发生。它们只是发生,然后你采取行动。想知道“何时”或试图弄清楚“如何”会打破这种本性。

    也许在这种情况下,您不需要基于事件的方法来完成工作?

    Jon Skeet 所说的对于当前的实现在技术上是正确的,但在 c#8.5 或 VBasic 15.0 中可能不会。依赖实施细节总是弊大于利。

    【讨论】:

      【解决方案5】:

      一般来说,事件订阅者的行为应该彼此独立。无论是按订阅顺序、反向订阅顺序还是以看似随机的顺序(每次引发事件时任意变化)调用它们都应该没有区别。订阅者不应该关心在他们之前或之后执行的其他订阅者。

      然而,在某些情况下,事件可能会在这种排序很重要的上下文中使用。事件处理程序可能会被传递一个可变对象,并被期望利用先前处理程序对该对象的突变。在这种情况下,如果事件的有意义的操作需要它们以特定的顺序执行,并且已经遵守了对订阅者的任何书面要求,那么人们应该期望事件将按照给定的顺序执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-23
        • 2019-08-05
        • 2021-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多