我已阅读过帖子here和文章here 我有一个计时器事件,每隔一段时间触发一次,我想在处理程序中进行一些异步处理,所以有类似的东西:
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文章here csays
Void-returns async方法有一个特定的目的:make 异步事件处理程序可能。
Timer.Elapsed我认为同步事件处理程序是否仍然可以附加async void
?
答案 0 :(得分:7)
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;
为void
方法返回async
并不理想,但对于事件处理程序,无论如何都没有代码会使用Task
(除非事件是专门用于理解async
方法,如Asynchronous events in C#)。如果你从中获得零利益,那么没有理由向后弯腰以遵守原本正确的编码实践。
另请参阅Should I avoid 'async void' event handlers?
的附录:强>
从编辑到问题:
Timer.Elapsed我认为同步事件处理程序是否仍然可以附加
async void
?
不是异步或同步的事件,而是处理程序本身。这完全取决于您是否使用async
和await
作为处理程序方法。正如您的问题和我的回答所述,您可以使用async void
处理程序方法和Elapsed
事件,就像您可以使用任何其他事件一样(假设事件签名需要void
as处理程序返回类型,这当然是传统.NET事件的标准。)
答案 1 :(得分:0)
你是否正确避免“异步无效”。不确定编译器没有反对,但你订阅了同一个事件两次。
您应该将异步部分保留在处理程序中,而不是调用处理程序。
尝试删除重复的事件订阅:
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<string>
。
此外,由于这是在Windows服务内部,请不要忘记在必要时取消订阅。