У меня есть репозиторий данных, который обеспечивает уровень сохранения для моделей моего приложения. Весь доступ к диску является асинхронным, поэтому весь мой уровень сохранения написан с помощью async/await. Мой хранилище данных позволяет другим модулям подписаться на изменения в данных:В ожидании выполнения обработчиков событий
public event EventHandler<Journaling.DataChangeEventArgs> DataChanged;
protected void OnDataChanged(Journaling.Action a)
{
if (DataChanged != null)
{
DataChanged(this, new Journaling.DataChangeEventArgs(a));
}
}
Когда я говорю хранилище, чтобы удалить объект, на который ссылается на другие объекты, он удаляет эти другие объекты.
public async Task<bool> DeleteAsync(Models.BaseModel model)
{
await DeleteDependentModelsAsync(model).ConfigureAwait(false);
if (await connection.DeleteAsync(model).ConfigureAwait(false) != 1)
return false;
else
{
var deleteAction = new Journaling.DeleteAction(model);
OnDataChanged(deleteAction);
return true;
}
}
Эта настройка работает в некоторой степени, но у меня есть проблема при удалении объектов, которые ссылаются на другие объекты. Рассмотрим следующий пример:
Object X
Object A1: references X
Object A2: references X
Object A3: references X
У меня есть модуль регистратора, который подписывается на изменения в хранилище данных, и выводит их в файл. Журналу иногда требуется получить дополнительные данные из репозитория, чтобы сделать его доступным для чтения человеком. Бревно при удалении объекта X должно быть:
A1 deleted (parent: X, more information contained in X)
A2 deleted (parent: X, more information contained in X)
A3 deleted (parent: X, more information contained in X)
X deleted
Проблема заключается в том, что OnDataChange не ожидают выполнения обработчиков событий. Из-за этого репозиторий данных удаляет A1-A3, а затем X до того, как обработчик событий регистратора даже вызывается один раз. Но обработчик события должен получить некоторую информацию о X, что уже невозможно, поскольку хранилище данных уже удалено X.
Мне как-то придется ждать выполнения обработчика событий в OnDataChanged. Таким образом, я мог бы убедиться, что журнал завершил свою работу до того, как следующий объект будет удален из хранилища.
Может ли кто-нибудь намекнуть мне в правильном направлении о том, как это сделать? Я рассмотрел использование семафоров, но это сломало бы свободную связь между хранилищем данных и регистратором.
Учитывая эту модель, для обработчика такого события кажется необычайно легким, чтобы не знать, что им нужно, чтобы они «использовали» там, или даже если знали, иногда забывали. Когда делегат обработчика возвращает «Задача», это делает намного сложнее для любого, добавляющего обработчик, чтобы каким-то образом не указать на завершение. Они * могли *, но им нужно было бы более или менее пытаться стрелять в ногу, что гораздо меньше касается. Это добавляет немного работы коду, запускающему событие, но я думаю, что компромисс стоит. – Servy
Я думаю, что оба варианта жизнеспособны. Недостатками сигнатуры события, возвращающей задачу, является то, что она вынуждает всех обработчиков иметь асинхронную подпись и что она не поддерживает обратную совместимость. Это правда, что разработчики могут забыть отсрочки, но это общий шаблон в API WinStore, поэтому многие разработчики знакомы с ними. –
Если вас это беспокоит, вы можете делать то, что вы делаете для любого другого члена, который должен поддерживать как синхронные, так и асинхронные версии: предоставить оба. Имейте синхронное событие и асинхронное событие. – Servy