如何在C#中调用异步void事件处理程序?

时间:2014-12-01 12:30:47

标签: c# .net event-handling async-await

如果我将事件处理程序声明为async void,它们是否会被.NET框架同步或异步调用?

即,给出以下代码:

async void myButton_click(object sender, EventArgs e) {
   do stuff
   await longRunning()
   do more stuff
}

我可以确定在GUI线程上执行“do stuff”行吗?

2 个答案:

答案 0 :(得分:9)

事件处理程序将被同步调用,并且不等待(等待)直到事件处理程序完成,但等待直到事件处理程序返回。

如果上一句话容易混淆,我会尽力解释清楚。当执行所有等待点并且已到达方法体的末尾或执行任何return语句时,异步方法完成(忽略异常)。但是,只要您点击尚未完成的Task的第一个await语句,异步方法就会返回。换句话说,异步方法可以返回几次,但只能完成一次。

现在我们知道异步方法何时完成并返回。事件处理程序将假定您的方法一返回就完成了,而不是实际完成时。

一旦你的事件处理程序到达第一个await语句,它就会返回,如果有更多的方法附加到同一个事件处理程序,它将继续执行它们而不用等待异步方法来完成。

是的,如果UI线程触发事件,do stuff将在UI线程中执行,只要do more stuff未被调用,也将在UI线程中执行是longRunning().ConfigureAwait(false)

答案 1 :(得分:4)

将调用它们,就像调用任何其他非async-await方法一样:

Click(this, EventArgs.Empty);

因为此特定事件处理程序是async方法,所以调用将同步运行,直到达到await,其余的将是延续。 这意味着do stuff在GUI线程上同步执行。然后调用者继续前进,而不知道async操作尚未完成。

do more stuff也将在GUI线程上执行,但原因不同。 GUI环境中的SynchronizationContext确保将延续发布到单个GUI线程,除非您明确告诉它不要使用await longRunning().ConfigureAwait(false)