我有一个计时器事件,每隔一段时间触发一次,我想在处理程序内部进行一些异步处理,所以有类似的事情:
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 is “not recommended”,with one very important exception:
event handlers.
它的异步事件处理程序或同步事件处理程序是否重要?
Void-returning async methods have a specific purpose: to make
asynchronous event handlers possible.
Timer.Elapsed是我认为同步事件处理程序我还能将async void附加到它吗?
解决方法
你的代码编译得很好(第二个事件订阅……第一个会生成编译时错误,假设两个语句中都有相同的timer_Elapsed()方法),因为编译器可以推断委托的返回类型应该是无效的.异步匿名方法也可以返回Task,但在这种情况下,这将是错误的方法签名,因此您将获得void.
将事件句柄声明为async void也没关系:
private async void timer_Elapsed(object sender,ElapsedEventArgs e) { await Task.Delay(10); }
使用如下:
timer.Elapsed += timer_Elapsed;
对异步方法返回void并不理想,但在事件处理程序的情况下,没有代码将继续使用Task(除非事件是专门用于理解异步方法,如Asynchronous events in C#).如果您从这样做中获得零利益,那么没有理由向后弯腰以遵守原本正确的编码实践.
另见Should I avoid ‘async void’ event handlers?
附录:
从您的编辑到问题:
Timer.Elapsed is I think synchronous event handler can I still attach
async void
to it?
它不是异步或同步的事件,而是处理程序本身.这完全取决于您是否使用async并等待处理程序方法.您可以,如您的问题和我的答案中所述,使用带有Elapsed事件的异步void处理程序方法,就像您可以使用任何其他事件一样(假设事件签名需要void作为处理程序返回类型,这当然是标准对于传统的.NET事件).