http://www.wxzzz.com/650.html
避免 Async Void
Async 方法有三种可能的返回类型: Task、Task<T> 和 void,但是 async 方法的固有返回类型只有 Task 和 Task<T>。 当从同步转换为异步代码时,任何返回类型 T 的方法都会成为返回 Task<T> 的 async 方法,任何返回 void 的方法都会成为返回 Task 的 async 方法。 下面的代码段演示了一个返回 void 的同步方法及其等效的异步方法:
void MyMethod() { // Do synchronous work. Thread.Sleep(1000); } async Task MyMethodAsync() { // Do asynchronous work. await Task.Delay(1000); }
返回 void 的 async 方法具有特定用途: 用于支持异步事件处理程序。 事件处理程序可以返回某些实际类型,但无法以相关语言正常工作;调用返回类型的事件处理程序非常困难,事件处理程序实际返回某些内容这一概念也没有太大意义。 事件处理程序本质上返回 void,因此 async 方法返回 void,以便可以使用异步事件处理程序。 但是,async void 方法的一些语义与 async Task 或 async Task<T> 方法的语义略有不同。
Async void 方法具有不同的错误处理语义。 当 async Task 或 async Task<T> 方法引发异常时,会捕获该异常并将其置于 Task 对象上。 对于 async void 方法,没有 Task 对象,因此 async void 方法引发的任何异常都会直接在 SynchronizationContext(在 async void 方法启动时处于活动状态)上引发。 图 2 演示本质上无法捕获从 async void 方法引发的异常。
创建一个真正异步的异步函数
前面我们提到,await语句await到最后必然调用了一个启动了新线程的完成实际工作的真正异步的异步函数,那么如何自己定义一个这样的函数呢?其实很简单,使用Task类就可以创建这样一个函数,示例代码如下:
private async void Button_Click(object sender, RoutedEventArgs e) { resultsTextBox.Text += String.Format("\r\nMyAsync({0}).\r\n", Thread.CurrentThread.ManagedThreadId); while (true) resultsTextBox.Text += String.Format("\r\nMyAsync({0}): {1}.\r\n", Thread.CurrentThread.ManagedThreadId, await MyAsync()); } public Task<string> MyAsync() { var t = new Task<string>((str) => { var dt = DateTime.Now; Thread.Sleep(4000); return String.Format("({0}){1} - {2}", Thread.CurrentThread.ManagedThreadId, dt, DateTime.Now); }, null); t.Start(); return t; }运行结果如下: