是否可以将异步事件处理程序附加到System.Timers.Timer?

我已经在这里阅读了SOpost和文章这里我有一个计时器事件,每隔一段时间触发一次,我想在处理程序内部进行一些异步处理,所以有类似的事情:

Timer timer = new Timer(); timer.Interval = 1000; timer.Elapsed += timer_Elapsed; // Please ignore this line. But some answers already given based on this line so I will leave it as it is. timer.Elapsed += async (sender, arguments) => await timer_Elapsed(sender, arguments); private async Task timer_Elapsed(object sender, ElapsedEventArgs e) { await Task.Delay(10); } 

上面的代码编译和工作。

但我不确定为什么代码正在编译。 ElapsedEventHandler预期的签名是

  void timer_Elapsed(object sender, ElapsedEventArgs e) 

但是我的方法返回Task而不是void因为不建议使用async void 。 但这与ElapsedEventHandler签名不匹配,仍在编译和工作?

可以在Timer.Elapsed上调用asyn方法吗? 代码将在windows服务中执行。

更新1

async void是“不推荐”的,有一个非常重要的例外:事件处理程序。

它的异步事件处理程序或同步事件处理程序是否重要?

MSDN文章在这里 csays

返回exception的异步方法有一个特定的目的:使异步事件处理程序成为可能。

Timer.Elapsed是我认为同步事件处理程序我还能将async void附加到它吗?

async void是“不推荐”的,有一个非常重要的例外:事件处理程序。

你的代码编译得很好(第二个事件订阅……第一个会生成编译时错误,假设两个语句中都有相同的timer_Elapsed()方法),因为编译器可以推断委托的返回类型应该是voidasync匿名方法可以返回Task ,但在这种情况下,这将是错误的方法签名,因此您将获得void

将事件句柄声明为async void也没关系:

  private async void timer_Elapsed(object sender, ElapsedEventArgs e) { await Task.Delay(10); } 

使用如下:

 timer.Elapsed += timer_Elapsed; 

async方法返回void并不理想,但在事件处理程序的情况下,没有代码将继续使用Task (除非事件是专门用于理解async方法,如在C#中的异步事件中 )。 如果您从这样做中获得零利益,那么没有理由向后弯腰以遵守原本正确的编码实践。

另请参阅我应该避免’async void’事件处理程序吗?

附录:

从您的编辑到问题:

Timer.Elapsed是我认为同步事件处理程序我还能将async void附加到它吗?

它不是异步或同步的事件,而是处理程序本身。 这完全取决于您是否使用asyncawait处理程序方法。 您可以,如您的问题和我的答案中所述,使用带有Elapsed事件的async void处理程序方法,就像您可以使用任何其他事件一样(假设事件签名需要void作为处理程序返回类型,这当然是标准对于传统的.NET事件)。

你是否正确避免“异步无效”。 不确定编译器没有反对但你订阅了同一个事件两次。

您应该将异步部分保留在处理程序中,而不是调用处理程序。

尝试删除重复的事件订阅:

 timer.Elapsed += async (sender, arguments) => await timer_Elapsed(sender, arguments); 

并从以下位置更改处理程序的签名:

 private async Task timer_Elapsed(object sender, ElapsedEventArgs e) 

至:

 private void timer_Elapsed(object sender, ElapsedEventArgs e) 

然后在处理程序中执行异步部分,使用类似本文中的建议: https : //stackoverflow.com/a/31469699/6776481

除了“WrapSomeMethod”调用之外,只返回Task ,而不是Task

此外,由于这是在Windows服务内部,请不要忘记在必要时取消订阅该事件。