Я создаю класс, который имеет ряд событий, один из которых 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
, и поэтому создание async - это в основном огонь и забыть. Мой движок активно использует eventing для уведомления сторонних разработчиков (и нескольких внутренних компонентов) о том, что события происходят внутри движка и позволяют им реагировать на них.
Есть ли хороший маршрут, чтобы спуститься, чтобы заменить событие чем-то асинхронным, на котором я могу использовать? Я не уверен, должен ли я использовать BeginShutdownGame
и EndShutdownGame
с обратными вызовами, но это боль, потому что тогда только вызывающий источник может передать обратный вызов, а не какой-либо сторонний материал, который подключается к движку, который что я получаю с событиями. Если сервер вызывает game.ShutdownGame()
, то нет возможности подключать плагины и другие компоненты в двигателе по своим обратным вызовам, если я не подключу какой-либо метод регистрации, сохраняя коллекцию обратных вызовов.
Любые советы о том, какой предпочтительный/рекомендуемый маршрут будет сходить с этим, будут очень признательны! Я огляделся и по большей части увидел, что я использую подход Begin/End, который, как я думаю, не удовлетворит то, что я хочу делать.
Edit
Еще один вариант, который я рассматриваю, - это использовать метод регистрации, который требует ожидаемого обратного вызова. Я перебираю все обратные вызовы, захватываю их задачу и жду с помощью 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);
}