博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈。

  异步方法具有三个可让开发人员选择的返回类型:Task<TResult>、Task 和 void。

  什么时候需要使用哪一种返回类型,具体情况需要具体分析。如果使用不当,程序的执行结果也许并不是你想要的,下面我们就来好好谈谈如何针对不同的情况选择不同的返回类型。

目录

  • 返回类型 - Task<TResult>
  • 返回类型 - Task
  • 返回类型 - void
  • 小结

一、返回类型 - Task<TResult>

  【记住】当你添加 async 关键字后,需要返回一个将用于后续操作的对象,请使用 Task<TResult>。

   Task<TResult> 返回类型可用于 async 方法,其中包含指定类型 TResult

  在下面的示例中,GetDateTimeAsync 异步方法包含一个返回当前时间的 return 语句。 因此,方法声明必须指定 Task<DateTime>

        async Task<DateTime> GetDateTimeAsync()
{
//Task.FromResult 是一个占位符,类型为 DateTime
return await Task.FromResult(DateTime.Now);
}

  

  调用 GetDateTimeAsync 方法:

        async Task CallAsync()
{
//在另一个异步方法的调用方式
DateTime now = await GetDateTimeAsync();
}

  当 GetDateTimeAsync 从 await 表达式中调用时,await 表达式将检索存储在由 GetDateTimeAsync 返回的 task 中的 DateTime 类型值。

        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 变量。

  这次我演示不同的变量,你可以自己对比下结果是否相同:

        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

  【记住】你如果只是想知道执行的状态,而不需要知道具体的返回结果时,请使用 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 返回类型主要用在事件处理程序中。 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。

  • 请尽量优先使用 Task<TResult> 和 Task 作为 async 方法的返回类型。

async 的三大返回类型的更多相关文章

  1. [C#] async 的三大返回类型

    async 的三大返回类型 序 博主简单数了下自己发布过的异步文章,已经断断续续 8 篇了,这次我想以 async 的返回类型为例,单独谈谈. 异步方法具有三个可让开发人员选择的返回类型:Task&l ...

  2. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  3. springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序

    springMVC 返回类型选择 以及 SpringMVC中model,modelMap.request,session取值顺序 http://www.360doc.com/content/14/03 ...

  4. MySql学习 (一) —— 基本数据库操作语句、三大列类型

    注:该MySql系列博客仅为个人学习笔记. 在使用MySql的时候,基本都是用图形化工具,如navicat.最近发现连最基本的创建表的语法都快忘了... 所以,想要重新系统性的学习下MySql,为后面 ...

  5. C/C++函数调用的几种方式及函数名修饰规则以及c++为什么不允许重载仅返回类型不同的函数

    我们知道,调用函数时,计算机常用栈来存放函数执行需要的参数,由于栈的空间大小是有限的,在windows下栈是向低地址扩展的数据结构,是一块连续的内存区域.这句话的意思是栈顶的地址和栈的最大容量是系统预 ...

  6. C# web api返回类型设置为json的两种方法

    web api写api接口时默认返回的是把你的对象序列化后以XML形式返回,那么怎样才能让其返回为json呢,下面就介绍两种方法: 方法一:(改配置法) 找到Global.asax文件,在Applic ...

  7. 转:C++编程隐蔽错误:error C2533: 构造函数不能有返回类型

    C++编程隐蔽错误:error C2533: 构造函数不能有返回类型 今天在编写类的时候,出现的错误. 提示一个类的构造函数不能够有返回类型.在cpp文件里,该构造函数定义处并没有返回类型.在头文件里 ...

  8. iOS 用instancetype代替id作返回类型有什么好处?

    2014-07-07更新:苹果在iOS 8中全面使用instancetype代替id Steven Fisher:只要一个类返回自身的实例,用instancetype就有好处. @interface ...

  9. C# web api 返回类型设置为json的两种方法

    每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默.我眼中的程序员大多都不 ...

随机推荐

  1. 转载:linux系统下SVN同步文件到WEB目录

    SVN在团队开发中使用非常普遍,是一个很方便的版本控制系统.  如果要是能将SVN服务器上的数据自动发布到Web服务器,那将是整个项目开发.测试更加便捷.利用SVN的hook功能就能实现将SVN服务器 ...

  2. 【转】GGTalk即时通讯系统(支持广域网)终于有移动端了!(技术原理、实现、源码)

    原文地址:http://www.cnblogs.com/justnow/p/4836636.html 首先要感谢大家一直以来对于GGTalk即时通讯系统的关注和支持!GGTalk即时通讯系统的不断完善 ...

  3. nodejs express route 的用法

    express 中文社区:http://expressjs.jser.us/community.html nodejs express route 的用法 1. 首先是最基本的用法. 1 2 3 4 ...

  4. GridView中实现全选与取消全选,以便同时删除多条数据

    我们项目后台操作中不可避免的会有同时删除多项的操作,本文实现的就是当点击全选时,选定当前页中所有项,当取消了某一项的选定,则“全选”CheckBox的checked也为false:然后在后台中取到所选 ...

  5. MAC 通过brew安装软件

    1.安装brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/instal ...

  6. php安全处理

    1.php.ini 修改 open_basedir='d:\wwwroot' //配置只能访问指定的网站目录 2.php.ini 修改 disable_funcitons=system,passthr ...

  7. AspNet GridView Excel 下载 Excel 导出

    1.GridView AutoGenerateColums =false; DataSource DataBind 2.BoundField DataField HeaderText ItemStyl ...

  8. Mac 學習系列之Python Challenge 11-20

    11.给你一个正整数列表 L, 如 L=[2,8,3,50], 输出L内全部数字的乘积末尾0的个数, 如例子L的结果为2.(提示:不要直接相乘,数字非常多,可能溢出) Answer: n_2 = 0 ...

  9. Atitit. 衡量项目规模 ----包含的类的数量 .net java类库包含多少类 多少个api方法??

    Atitit. 衡量项目规模 ----包含的类的数量 .net java类库包含多少类 多少个api方法?? 1 framework 4.5 (10万个api)1 2 Jdk8   57M1 3 Gi ...

  10. 【Android】利用Fiddler进行抓包详解教程。抓取接口以及数据,可以抓真实安卓手机或者模拟器。

    大家都知道抓包的方法很多.我这里给大家介绍介绍一种,利用fiddler进行抓包,当然比如Wireshark也可以抓包,我们这里不做介绍.我这里演示的是fiddler+天天模拟器,当然真实安卓手机也是一 ...