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

我已经阅读过这里和这里发布的文章我有一个定时器事件,每隔一段时间触发一次,我想在处理程序中执行一些异步处理,所以沿着以下几行:

        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

异步无效是“不推荐”,有一个非常重要的异常:事件处理程序。

如果它的异步事件处理程序或同步事件处理程序有关系吗?

MSDN文章herecsays

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

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#中的异步事件一样)。 如果你从这样做中获得零利益,没有理由向后屈服以遵守那些正确的编码习惯。


另请参见我应该避免使用“异步无效”事件处理程序吗?


附录:

从你的编辑到问题:

Timer.Elapsed是我认为同步事件处理程序,我仍然可以将async void附加到它?

事件不是异步或同步的,而是处理器本身。 这完全取决于是否使用asyncawait处理程序方法。 您可以像您的问题和我的回答中所述,使用async void处理程序方法和Elapsed事件,就像您可以使用任何其他事件一样(假设事件签名需要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<string>

此外,由于这是在Windows服务中,所以不要忘记在必要时退订事件。

链接地址: http://www.djcxy.com/p/93009.html

上一篇: Is it okay to attach async event handler to System.Timers.Timer?

下一篇: Share AI key between between multiple web apps and services?