Я створюю клас, який має низку подій, одна з них 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
і тому його асинхронізація - це, в основному, запуск і забуття. Мій движок активно використовує події, щоб повідомляти сторонніх розробників (і кілька внутрішніх компонентів) про те, що події відбуваються в двигуні, і дозволяючи їм реагувати на них.
Чи є хороший шлях, який можна спустити, щоб замінити eventing чимось асинхронним, що я можу використовувати? Я не впевнений , якщо я повинен використовувати BeginShutdownGame
і EndShutdownGame
з зворотними викликами, але це біль , тому що тільки тоді викликає джерело може передати функцію зворотного виклику, а не якась - або третя річ партії, штекери до двигуна, який є тим, що я отримую з подіями . Якщо сервер дзвонить game.ShutdownGame()
, плагіни двигуна та / або інші компоненти движка не можуть передавати свої зворотні виклики, якщо я не підключаю якийсь спосіб реєстрації, зберігаючи колекцію зворотних викликів.
Будемо дуже вдячні за будь-яку пораду щодо того, яким найкращим / рекомендованим маршрутом рухатись цим шляхом! Я озирнувся навколо і здебільшого те, що я бачив, використовує підхід Begin / End, який, думаю, не задовольнить того, що я хочу зробити.
Редагувати
Ще одним варіантом, який я розглядаю, є використання методу реєстрації, який приймає очікуваний зворотний дзвінок. Я переглядаю всі зворотні виклики, захоплюю їх Завдання і чекаю з 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);
}