我正在创建一个有一系列事件的类,其中之一就是 GameShuttingDown
。触发此事件时,我需要调用事件处理程序。此事件的目的是通知用户游戏正在关闭,他们需要保存他们的数据。保存是可以等待的,而事件是不可以等待的。所以当处理程序被调用时,游戏会在等待的处理程序完成之前关闭。
public event EventHandler<EventArgs> GameShuttingDown;
public virtual async Task ShutdownGame()
{
await this.NotifyGameShuttingDown();
await this.SaveWorlds();
this.NotifyGameShutDown();
}
private async Task SaveWorlds()
{
foreach (DefaultWorld world in this.Worlds)
{
await this.worldService.SaveWorld(world);
}
}
protected virtual void NotifyGameShuttingDown()
{
var handler = this.GameShuttingDown;
if (handler == null)
{
return;
}
handler(this, new EventArgs());
}
// The game gets shut down before this completes because of the nature of how events work
DefaultGame.GameShuttingDown += async (sender, args) => await this.repo.Save(blah);
我知道事件的签名是 void EventName
,因此使其异步基本上是触发和忘记。我的引擎大量使用事件来通知第三方开发人员(以及多个内部组件)在引擎中发生的事件,并让他们对事件作出反应。
有没有一种好的方法可以用我可以使用的基于异步的东西来替换事件?我不确定我是否应该使用 BeginShutdownGame
和 EndShutdownGame
进行回调,但这是一个痛苦的,因为只有调用源可以传递一个回调,而不是任何第三方的东西,插入到引擎,这就是我得到的事件。如果服务器调用 game.ShutdownGame()
,那么引擎插件和引擎内的其他组件就无法传递它们的回调函数,除非我连接某种注册方法,保留一组回调函数。
任何关于首选/推荐路线的建议,我们将不胜感激!我环顾四周,大多数情况下,我所看到的是使用开始/结束方法,我认为这不会满足我想要做的事情。
剪辑
我正在考虑的另一种选择是使用注册方法,该方法接受可等待的回调。我迭代所有的回调函数,获取它们的 Task 并使用 WhenAll
等待。
private List<Func<Task>> ShutdownCallbacks = new List<Func<Task>>();
public void RegisterShutdownCallback(Func<Task> callback)
{
this.ShutdownCallbacks.Add(callback);
}
public async Task Shutdown()
{
var callbackTasks = new List<Task>();
foreach(var callback in this.ShutdownCallbacks)
{
callbackTasks.Add(callback());
}
await Task.WhenAll(callbackTasks);
}