假设按订阅顺序调用事件订阅者是否安全? 示例:
void One(object sender, EventArgs e) {}
void Two(object sender, EventArgs e) {}
event EventHandler foo;
foo += One;
foo += Two;
当事件被触发时,One()总是在Two()之前被调用吗?
编辑:
你应该不依赖它,我只是想。这个想法是,多播代表与COMMAND模式类似。所以我只是想知道。通常你会使用一个保存COMMAND命令的集合,这样你就可以撤消/重做/无论如何。
答案 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>