博主简单数了下本身发布过的异步文章,已经断断续续 8 篇了,此次我想以 async 的返回类型为例,单独谈谈。html
异步方法具备三个可以让开发人员选择的返回类型:Task<TResult>、Task 和 void。 异步
何时须要使用哪种返回类型,具体状况须要具体分析。若是使用不当,程序的执行结果也许并非你想要的,下面咱们就来好好谈谈如何针对不一样的状况选择不一样的返回类型。async
【记住】当你添加 async 关键字后,须要返回一个将用于后续操做的对象,请使用 Task<TResult>。post
Task<TResult> 返回类型可用于 async 方法,其中包含指定类型 TResult
。url
在下面的示例中,GetDateTimeAsync 异步方法包含一个返回当前时间的 return 语句。 所以,方法声明必须指定 Task<DateTime>
。spa
async Task<DateTime> GetDateTimeAsync() { //Task.FromResult 是一个占位符,类型为 DateTime return await Task.FromResult(DateTime.Now); }
调用 GetDateTimeAsync 方法:code
async Task CallAsync() { //在另外一个异步方法的调用方式 DateTime now = await GetDateTimeAsync(); }
当 GetDateTimeAsync 从 await 表达式中调用时,await 表达式将检索存储在由 GetDateTimeAsync 返回的 task 中的 DateTime 类型值。 htm
async Task CallAsync() { //在另外一个异步方法的调用方式 //DateTime now = await GetDateTimeAsync(); //换种方式调用 Task<DateTime> t = GetDateTimeAsync(); DateTime now = await t; }
经过 CallAsync 方法对 GetDateTimeAsync 方法的调用,对非当即等待的方法 GetDateTimeAsync 的调用返回 Task<DateTime>
。 该任务指派给示例中的 DateTime 的 Task
变量。 由于 DateTime 的 Task
变量是 Task<DateTime>,也就是说这里的 TResult
就是 DateTime 类型。 在这种状况下,TResult 表示日期类型。 当 await
应用于 Task<DateTime>,await 表达式的计算结果为 Task<DateTime> 的 DateTime 类型的内容。同时,该值会分配给 now 变量。对象
此次我演示不一样的变量,你能够本身对比下结果是否相同:blog
async Task CallAsync() { //在另外一个异步方法的调用方式 DateTime now = await GetDateTimeAsync(); //换种方式调用 Task<DateTime> t = GetDateTimeAsync(); DateTime now2 = await t;
//输出的结果对比 Console.WriteLine($"now: {now}"); Console.WriteLine($"now2: {now2}"); Console.WriteLine($"t.Result: {t.Result}"); }
我这边能够给出的答案就是:结果是同样的。
【注意】task 的 Result 属性为锁定属性。若是你在该 task 完成以前尝试读取该属性值,会出现的结果是,当前处于活动状态的 thread 将被阻塞,阻塞到该 task 完成且结果值为可用时。 在大多数状况下,你都应经过使用 await
访问属性值,而不是直接访问该属性。
【记住】你若是只是想知道执行的状态,而不须要知道具体的返回结果时,请使用 Task。
不包含 return 语句,或者说不包含返回值的 return 语句的 async 方法一般具备返回类型 Task。若是这样的同步方法被编写为 async 的,这些方法实际上也是返回 void 的方法。 若是在异步方法中使用 Task
返回类型,调用方法可使用 await 运算符暂停调用方的完成,直至被调用的 async 方法结束。
请看示例:
async Task DelayAsync() { //Task.Delay 是一个占位符,用于假设方法正处于工做状态。 await Task.Delay(100); Console.WriteLine("OK!"); }
经过使用 await 语句而不是 await 表达式来调用和等待 DelayAsync 方法,相似于返回 void 的方法的调用语句。 await 运算符的应用程序在这种状况下不生成值。
请看调用 DelayAsync 的示例。
//调用和等待方法在同一声明中 await DelayAsync();
如今,我用将调用和等待的方法进行分离:
//分离 Task delayTask = DelayAsync(); await delayTask;
【记住】若是在触发后,你不想管了,请使用 void。如事件处理程序。
void 返回类型主要用在事件处理程序中。 void 返回类型还可用来替代不返回任何东西的方法,或者用于执行可分类为"调用后无论了"活动的方法。 可是,你都应尽量地返回类型 Task
,由于,不能 await 返回类型为 void 的 async 方法。 async 方法的任何调用方只可以继续完成(意味着有可能会出现 thread 阻塞),而无需等待调用的 async 方法完成,而且调用方应该,或者说必须独立于 async 方法生成的任何值或 exception。
返回 void 的 async 方法的调用方没法 catch 从该方法引起的 exception,而且,这种未经处理的 exception 可能会致使你的程序出现难以发现的故障。 若是返回 Task 类型或 Task<TResult> 类型的 async 方法中出现 exception,这种 exception 将存储于返回的任务中,并将在 await 该任务时再次触发。也就是说,请尽可能优先使用 Task<TResult> 和 Task,这样,调用方才能从中读取异常信息,并选择如何处理。
如今,异常也可使用 await 了,请移步到这里 《回眸 C# 的前世此生 - 见证 C# 6.0 的新语法特性》。
void 返回值示例:
private async void button1_Click(object sender, EventArgs e) { //启动进程并等待完成 await Task.Delay(100); }
当你添加 async 关键字后,须要返回一个将用于后续操做的对象,请使用 Task<TResult>;
你若是只是想知道执行的状态,而不须要知道具体的返回结果时,请使用 Task;
若是在触发后,你不想管了,请使用 void。