返回
顶部

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;
    }
}

image-20211230233304140

可以看到异步方法被调用之后,并不会立刻返回,而是去执行方法体中的代码,当执行到await修饰的异步方法时会立即返回到主方法,同时异步方法GetByteArrayAsync开始下载数据

最后在Main方法中使用await操作符获取异步方法的返回值

Task类

你在读上面的代码时候可能会产生一个疑问,DownloadDocsMainPageAsync的返回值明明是一个Task<int>类型的,为什么却可以写出下面的代码呢?

int bytesLoaded = await downloading;

这里就体现出await操作符的作用了,在C#中,Task<?>表示一个可以返回?类型返回值的方法

如果我们把await操作符删除掉,就会出现如下错误

image-20211230234053785

只有使用await操作符才可以获取到异步方法中Task<?>中的?类型的返回值

结语

没有系统学习过C#,参考着文档以及示例代码琢磨的,大概率有说的不对的地方,希望大家可以指正