await & async模式是C#中一个很重要的特性,可以用来提高异步程序(多线程程序)的执行效率。但是如果尝试用await关键字来await一个为null的Task对象,会导致程序抛出NullReferenceException异常。

新建一个.NET Core控制台项目,贴入如下代码:

using System;
using System.Threading;
using System.Threading.Tasks; namespace AwaitNull
{
class Program
{
/// <summary>
/// AwaitNullTask方法中的代码会await一个为null的Task t,这样做会抛出NullReferenceException异常
/// </summary>
static async Task AwaitNullTask()
{
Task t = null;//声明一个为null的Task对象t try
{
await t;//await为null的Task对象t,会导致这里抛出NullReferenceException异常 Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Await finished...");//由于上面抛出了异常,这里的Console.WriteLine不会被执行
}
catch(NullReferenceException e)
{
//输出异常信息
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : AwaitNullTask threw Exception : {e.GetType().ToString()}");
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Exception message : {e.Message}"); throw;//catch后继续抛出NullReferenceException异常到AwaitNullTask方法的外部
}
} static void Main(string[] args)
{
Task taskReturned = AwaitNullTask();//很有意思的是虽然AwaitNullTask方法内部抛出了NullReferenceException异常,但是其并不会影响AwaitNullTask方法外部的方法,就好像AwaitNullTask方法是在另外一个线程上执行的一样,但是本例中我们没有用Task来启动任何线程,可以看到本例中所有Console输出的信息中Thread id都相同,是在同一个线程上 Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : taskReturned status is : {taskReturned.Status.ToString()}");//输出AwaitNullTask方法返回的Task对象taskReturned的Status,由于AwaitNullTask方法内部抛出了异常,所以Task对象taskReturned的Status为Faulted Console.WriteLine();
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Press any key to quit...");
Console.ReadKey();
}
}
}

输出结果如下:

我们可以看到AwaitNullTask方法中由于await了一个为null的Task对象,抛出了NullReferenceException异常,但是有意思的是,AwaitNullTask方法表现出的行为是貌似运行在另一个线程上一样,其抛出的NullReferenceException异常并不会影响到Main方法,但实际上Main方法和AwaitNullTask方法都是由同一个线程运行的。

所以我们在使用await关键字等待一个Task或Task<T>对象时,最好加上一个判断逻辑,只有在Task或Task<T>对象不为null时,才进行await。所以我们更改本例中上面的代码如下:

using System;
using System.Threading;
using System.Threading.Tasks; namespace AwaitNull
{
class Program
{
/// <summary>
/// 现在我们在AwaitNullTask方法中加了判断逻辑,只有在Task对象不为null时,才进行await,避免抛出异常
/// </summary>
static async Task AwaitNullTask()
{
Task t = null;//声明一个为null的Task对象t try
{
//判断Task对象t是否为null,不为null才执行下面的await
if (t != null)
{
await t;//因为现在上面的if存在,这里的await就不会被执行了,避免了异常的抛出
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Await finished...");
}
}
catch(NullReferenceException e)
{
//输出异常信息
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : AwaitNullTask threw Exception : {e.GetType().ToString()}");
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Exception message : {e.Message}"); throw;//catch后继续抛出NullReferenceException异常到AwaitNullTask方法的外部
} //返回类型为Task的异步方法(使用了async关键字的方法),可以不返回任何值,或者使用return;也可以,.NET会在异步方法结束时自动构造一个Task对象,作为异步方法的返回值
} static void Main(string[] args)
{
Task taskReturned = AwaitNullTask();//这次AwaitNullTask方法没有抛出异常成功返回 Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : taskReturned status is : {taskReturned.Status.ToString()}");//由于AwaitNullTask方法成功返回,所以此时Task对象taskReturned的Status为RanToCompletion,表示AwaitNullTask方法成功执行完毕
//比较有意思的是虽然我们在AwaitNullTask方法中没有return任何东西,但是AwaitNullTask方法还是返回了一个不为null的Task对象taskReturned,并且我们还在上面输出了Task对象taskReturned的Status值,说明.NET为AwaitNullTask方法构造了一个Task对象作为返回值 Console.WriteLine();
Console.WriteLine($"Thread id <{Thread.CurrentThread.ManagedThreadId}> : Press any key to quit...");
Console.ReadKey();
}
}
}

输出结果如下:

所以这次AwaitNullTask方法就不会抛出异常了,成功执行完毕。

C#中如果用await关键字来await一个为null的Task对象会抛出异常的更多相关文章

  1. Async 与 Await 关键字研究

    1        Aynsc 和 Await 关键字的研究 在 .NET 4.0 以后,基于 Task 的异步编程模式大行其道,因其大大简化了异步编程所带来的大量代码工作而深受编程人员的欢迎,如果你曾 ...

  2. C#中的异步编程Async 和 Await

    谈到C#中的异步编程,离不开Async和Await关键字 谈到异步编程,首先我们就要明白到底什么是异步编程. 平时我们的编程一般都是同步编程,所谓同步编程的意思,和我们平时说的同时做几件事情完全不同. ...

  3. .NET中的async和await关键字使用及Task异步调用实例

    其实早在.NET 4.5的时候M$就在.NET中引入了async和await关键字(VB为Async和Await)来简化异步调用的编程模式.我也早就体验过了,现在写一篇日志来记录一下顺便凑日志数量(以 ...

  4. 浅谈async、await关键字 => 深谈async、await关键字

    前言 之前写过有关异步的文章,对这方面一直比较弱,感觉还是不太理解,于是会花点时间去好好学习这一块,我们由浅入深,文中若有叙述不稳妥之处,还请批评指正. 话题 (1)是不是将方法用async关键字标识 ...

  5. 多线线程async与await关键字

    创建线程 //这里面需要注意的是,创建Thread的实例之后,需要手动调用它的Start方法将其启动. //但是对于Task来说,StartNew和Run的同时,既会创建新的线程,并且会立即启动它. ...

  6. WebApi上传图片 await关键字

    await关键字对于方法执行的影响 将上一篇WebApi上传图片中代码修改(使用了await关键字)如下: [HttpPost] public async Task<string> Pos ...

  7. async和await关键字实现异步编程

    async和await关键字实现异步编程 异步编程   概念 异步编程核心为异步操作,该操作一旦启动将在一段时间内完成.所谓异步,关键是实现了两点:(1)正在执行的此操作,不会阻塞原来的线程(2)一旦 ...

  8. 为什么我们要使用Async、Await关键字

    前不久,在工作中由于默认(xihuan)使用Async.Await关键字受到了很多质问,所以由此引发这篇博文“为什么我们要用Async/Await关键字”,请听下面分解: Async/Await关键字 ...

  9. 异步编程Async/await关键字

    异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ...

随机推荐

  1. JS深拷贝继承

    所谓深拷贝,就是子对象不紧继承父对象的非引用属性,还能继承父对象的引用属性(Object,Array),当子对象对继承的引用类型属性做修改时,父对象的引用类型不会被修改. 我们先写个浅拷贝的封装函数: ...

  2. 【PyQt5 学习记录】002:添加部件及网格布局

    #!/usr/bin/python3 # -*- coding:utf-8 -*- import sys from PySide2.QtWidgets import (QApplication, QW ...

  3. 原生Ajax(XMLHttpRequest)

    一.什么是Ajax: 全称Asynchronous JavaScript and XML: 异步的 JavaScript 和 XML: 可以在不重新加载整个页面的情况下(偷偷发数据),与服务器交换数据 ...

  4. js解决千分符问题[收藏下]

    //js数字千分符处理 function commafy(num) { num = num + ""; var re = /(-?\d+)(\d{3})/ while (re.te ...

  5. Oql实体转自定义对象

    返回单体: GroupEnvironmentDTO 是自定义的一个DTO, GroupEnvironmentEntity.MapToPOCO(dto);  把上述查出来的对象转换为DTO 返回实体集合 ...

  6. Python power spectral 功率谱

    You can also use scipy.signal.welch to estimate the power spectral density using Welch’s method. Her ...

  7. Monkey测试环境搭建

    一.JAVA环境的搭建 1.安装jdk-7u60-windows-x64(JAVA1.7.0,也可安装最新版的JAVA1.8.0),默认安装路径C盘: 2.JAVA环境变量的搭建: 我的电脑→右键属性 ...

  8. Java代码调用存储过程和存储方法

    准备一个oracle 的JDBC jar 包:ojdbc14_11g.jar 首先找到你的 oracle 安装位置,例如: 1.创建一个JDBC数据库连接工具类: package com.test.d ...

  9. 沉淀再出发:ELK使用初探

    沉淀再出发:ELK使用初探 一.前言 ELK是Elasticsearch.Logstash.Kibana的简称,这三者是核心套件,但并非全部. 最近ElasticSearch可以说是非常火的一款开源软 ...

  10. 为Linux设置IPTables防火墙

    我们 来讨论一下如何为你的CentOS 服务器来设置简单的防火墙. 这里我们以DigitalOcean的CentOS 6 VPS为基础来讨论的,同样也适用于 阿里云上其他类型的LINUX系统. (阿里 ...