是否可以将异步事件处理程序附加到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()
方法),因为编译器可以推断委托的返回类型应该是void
。 async
匿名方法也可以返回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
附加到它吗?
它不是异步或同步的事件,而是处理程序本身。 这完全取决于您是否使用async
并await
处理程序方法。 您可以,如您的问题和我的答案中所述,使用带有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服务内部,请不要忘记在必要时取消订阅该事件。