.net 在事件处理程序中处理异步操作的正确模式是什么?

.net 在事件处理程序中处理异步操作的正确模式是什么?,.net,task,.net,Task,我完全不喜欢异步编程的“一路走下去”哲学。然而,在.Net中有许多地方,您无法控制调用签名。我想到了事件处理程序。事件处理程序没有返回类型(毕竟它们是事件): 如果我使用这个模式,分析器会标记我应该通过使用wait来观察waitiable。这不是处理程序中的选项。所以我尝试了这个模式: protected virtual void OnThresholdReached(EventArgs e) { Task.Run(async () => await Task.Delay(0).C

我完全不喜欢异步编程的“一路走下去”哲学。然而,在.Net中有许多地方,您无法控制调用签名。我想到了事件处理程序。事件处理程序没有返回类型(毕竟它们是事件):

如果我使用这个模式,分析器会标记我应该通过使用wait来观察waitiable。这不是处理程序中的选项。所以我尝试了这个模式:

protected virtual void OnThresholdReached(EventArgs e)
{
    Task.Run(async () => await Task.Delay(0).ConfigureAwait(false)).Wait();
}
我被告知等待同步任务会导致死锁。有人建议使用“JoinableTaskFactory.Run”,但这是一个VisualStudio包,我不知道如何为一些应该成为核心方法的东西引入额外的包


那么,在事件处理程序中处理长时间运行的任务的最佳实践是什么呢?

使处理程序异步无效,删除task.Run(在这里没有任何用处,实际上在大多数真正异步的代码中也是如此),并确保以某种方式处理异常,方法是将整个块包装到try-catch中,至少记录它或以某种方式进行操作(在UI中显示错误)。如果您是事件的自动执行者,并且有权访问引发事件的代码,则还可以使事件异步。
protected virtual void OnThresholdReached(EventArgs e)
{
    Task.Run(async () => await Task.Delay(0).ConfigureAwait(false)).Wait();
}