возможно, мой подход совершенно неверен
Всякий раз, когда у вас возникает ситуация, когда вы хотите await
обработчик событий async
, это красный флаг.
События являются допустимым дизайном, используемым при реализации шаблона проектирования Observer . Тем не менее, они иногда неправильно используются в качестве дизайна при реализации шаблонов Strategy или Template Method . В синхронном мире вы можете избежать подобных замен - используя событие вместо интерфейса с одним методом. Но в асинхронном мире такая замена не работает.
Еще один хороший лакмусовый тест - рассмотреть ваше событие и спросить: «Действительно ли имеет смысл иметь несколько обработчиков?» Если ответ отрицательный, то, во-первых, событие не является правильным дизайном.
Тем не менее, если вы действительно хотите «асинхронное событие» вместо более правильного интерфейса с асинхронный метод, тогда есть пара опций . Один из них - вернуть делегату события Task
. Вы можете получить список обработчиков вручную и вызвать каждый из них. Вам просто нужно решить, хотите ли вы запускать все обработчики одновременно или выполнять их по одному. (И опять-таки, решение «мне нужно подождать их по одному» является убедительным признаком того, что событие - неправильный выбор дизайна).
Другой вариант - использовать «отсрочка», пропагандируемая UWP. Это позволяет использовать «нормальные» обработчики событий async void
, если они получают объект отсрочки. Вы можете сделать что-то подобное, используя DeferralManager
из AsyncEx
:
public sealed class MyEventArgs : EventArgs, IDeferralSource
{
private readonly IDeferralSource _deferralSource;
public MyEventArgs(IDeferralSource deferralSource)
{
_deferralSource = deferralSource;
}
public IDisposable GetDeferral() => _deferralSource.GetDeferral();
}
public event Action<object, MyEventArgs> MyEvent;
private async Task RaiseEventAsync()
{
var deferralManager = new DeferralManager();
var args = new MyEventArgs(deferralManager.DeferralSource);
MyEvent?.Invoke(this, args);
await deferralManager.WaitForDeferralsAsync();
}
Тогда любой обработчик async void
должен получить отсрочку как таковую:
private async void Handler(object source, MyEventArgs args)
{
using var deferral = args.GetDeferral();
await Task.Yield();
}