多个事件,一个处理程序调用一次

Mulitple Events, One handler called one time

TL;DR:即使我知道所有事件都会被触发,我能否让附加到许多事件的处理程序只触发一次?

我正在尝试收听一组对象,每个对象都将完成特定任务,然后通知所有者它已完成。为此,我只是遍历集合并为每个对象添加一个事件处理程序

foreach(var obj in collection)
{ 
  obj.Event += GroupHandler;
}

而且效果很好。但是,因为我知道任务将在大约同一时间完成,而且如果我早一点排队真的没关系,我想有一种方法来确保一旦 GroupHandler 被引发,它就不会再次被引发对于当前的执行集,所以我可以做类似的事情:

private void GroupHandler(object sender, EventArgs e)
{
   foreach(var obj in collection)
   {
     obj.QueueNext();
   }
}

理想情况下我会得到类似

的结果
private void GroupHandler(object sender, EventArgs e)
{
   if(GroupHandler.HasRun) return;

   foreach(var obj in collection)
   {
     obj.QueueNext();
   }
}

我知道我可以使用一些全局 bool(或者更可能是 int 来跟踪周期),但我不喜欢将其作为解决方案。我正在寻找比这更好的东西。

正如 Gusman 在评论中所说,您可以只让其中一个对象触发事件。这样你就知道每个事件集它只执行一次。

或者,您可以设置一个计时器、一个计数器和一个标志。在第一次事件执行时设置标志,然后启动计时器。只要设置了标志,就忽略其余事件。将您的计数器设置为您正在跟踪的对象的数量,并在每个对象触发其事件时递减计数器。当计时器到期或计数器达到零时,重置标志,重置计数器并取消计时器。这可能会很快变得复杂,并且可能会出现很多极端情况,所以如果您不太关心时间安排,那么第一种方法会好得多。尽量简化。

我最终使用了 Gusman 在评论中提到的内容并删除了事件处理程序。不过,真正的关键是找出重新连接它们的位置。所以我最终在 QueueNext 调用中传递了处理函数。

代码如下所示

private void GroupHandler(object sender, EventArgs e)
{
   foreach(var obj in collection)
   {
     obj.Event -= GroupHandler;
   }

   foreach(var obj in collection)
   {
     obj.QueueNext(GroupHandler);
   }
}

QueueNext 看起来像

public void QueueNext(EventHandler nextHandler)
{
   this.Event += nextHandler
   QueueNext();
}

这样事件只调用一次,每次执行都会调用