references:
前言
最近在看一个使用.Net实现的Kerberos库的代码,全是C#代码,里面很多语法都不太懂,这里做一下记录
正文
废话不多说,先上代码:
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class AwaitOperator
{
public static async Task Main()
{
Task<int> downloading = DownloadDocsMainPageAsync();
Console.WriteLine($"{nameof(Main)}: Launched downloading.");
int bytesLoaded = await downloading;
Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
}
private static async Task<int> DownloadDocsMainPageAsync()
{
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");
var client = new HttpClient();
byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/");
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
return content.Length;
}
}
await
操作符会将使用async
关键字修饰的方法挂起,我不太确定挂起这个说法准不准确,我们拿上面的代码来说,DownloadDocsMainPageAsync
方法被调用之后会理解返回到Main
方法中,也就是说它不会阻塞Main
方法的执行
Main
方法会在await
操作符出现的地方阻塞,而此时DownloadDocsMainPageAsync
方法已经执行了一段时间了,当然在上面的代码中体现不出来,因为在方法调用和真正用到方法返回值之间只有一个简单的输出
此时Main
方法会等待DownloadDocsMainPageAsync
异步方法的返回值,而在该方法中,它也正在等待GetByteArrayAsync
方法的返回值,当这两个方法依次完成异步操作之后,Main
方法继续执行剩余的代码
我们可以在Main
方法中加一个Sleep来更直观地看到异步执行的效果:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class AwaitOperator
{
public static async Task Main()
{
Task<int> downloading = DownloadDocsMainPageAsync();
Console.WriteLine($"{nameof(Main)}: Launched downloading.");
for (var i=0; i<5; i++){
Console.WriteLine("tick tock...");
Thread.Sleep(1000);
}
int bytesLoaded = await downloading;
Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
}
private static async Task<int> DownloadDocsMainPageAsync()
{
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");
var client = new HttpClient();
byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/");
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
return content.Length;
}
}
可以看到异步方法被调用之后,并不会立刻返回,而是去执行方法体中的代码,当执行到await
修饰的异步方法时会立即返回到主方法,同时异步方法GetByteArrayAsync
开始下载数据
最后在Main
方法中使用await
操作符获取异步方法的返回值
Task类
你在读上面的代码时候可能会产生一个疑问,DownloadDocsMainPageAsync
的返回值明明是一个Task<int>
类型的,为什么却可以写出下面的代码呢?
int bytesLoaded = await downloading;
这里就体现出await
操作符的作用了,在C#中,Task<?>
表示一个可以返回?
类型返回值的方法
如果我们把await
操作符删除掉,就会出现如下错误
只有使用await
操作符才可以获取到异步方法中Task<?>
中的?
类型的返回值
结语
没有系统学习过C#,参考着文档以及示例代码琢磨的,大概率有说的不对的地方,希望大家可以指正