事件订阅者是按订阅顺序调用的吗?

时间:2008-12-17 12:29:11

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

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

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

event EventHandler foo;

foo += One;
foo += Two;

当事件被触发时,One()总是在Two()之前被调用吗?

编辑:
你应该不依赖它,我只是想。这个想法是,多播代表与COMMAND模式类似。所以我只是想知道。通常你会使用一个保存COMMAND命令的集合,这样你就可以撤消/重做/无论如何。

5 个答案:

答案 0 :(得分:40)

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

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

要明确,订阅事件处理程序只意味着调用事件的相应“添加”部分。如果事件通过执行以下操作来处理此事:

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

然后将以相反的顺序调用处理程序。

摘要:对于所有理智的事件,您可以依赖订购。从理论上讲,事件可以做他们喜欢的事情,但我从未见过没有保持适当排序的事件。

答案 1 :(得分:23)

非常关注Jon Skeet给出的警告 - “鉴于实施......”。换句话说,做出最轻微的改变(多线程,其他处理程序等),你就有可能失去执行顺序的不变性。

NOT 依赖于事件排序。所有事件调度都应该在逻辑上独立,就好像它们是并行发生的一样。事件是逻辑上独立的行为。

我会更进一步,断言如果你必须承担一个事件发生的命令,你就会有严重的设计缺陷和/或滥用事件。

答案 2 :(得分:11)

即使以正确的顺序调用它们,我也会尝试不编写依赖于前一个委托被解雇的代码以使其正常运行。

如果Two()依赖于One()正在做的事情,那么要么附加一个以正确顺序调用这两个方法的委托,要么让Two()在必要时调用One()。

答案 3 :(得分:4)

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

事件本质上是异步的。这意味着您不会等待事件被触发或期望在给定时间发生。他们刚刚发生,然后你采取行动。想知道'何时'或试图找出'如何'将打破这种性质。

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

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

答案 4 :(得分:0)

通常,事件订阅者应该彼此独立行事。它们是按照订阅的顺序,订阅的逆序还是以每次事件发生时任意变化的看似随机顺序调用的,都没有区别。订阅者不应该关心在他们之前或之后执行的其他订阅者。

但是,在某些情况下,事件可能会在这种排序很重要的情况下使用。事件处理程序可以传递一个可变对象,并且应该使用该对象的先前处理程序的突变。在这种情况下,如果事件的有意义操作要求它们以特定顺序执行,并且只要符合订阅者的任何记录要求,就应该期望事件将按给定的顺序执行。 / p>