为什么有些异步方法需要返回类型的Task,而有些则不需要

1 c# asynchronous task-parallel-library async-await

在Microsoft的此示例中,该方法的返回类型为Task<int>

例1:

async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync. 
    //  - AccessTheWebAsync can't continue until getStringTask is complete. 
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    //  - Control resumes here when getStringTask is complete.  
    //  - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask;

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length;
}
Run Code Online (Sandbox Code Playgroud)

在第二个例子中,它使用async和await,但是不返回任何类型的Task <>,为什么?

例2:

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            ReadCharacters();
        }

        static async void ReadCharacters()
        {
            String result;
            using (StreamReader reader = File.OpenText("existingfile.txt"))
            {
                Console.WriteLine("Opened file.");
                result = await reader.ReadToEndAsync();
                Console.WriteLine("Contains: " + result);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第三,在第一个例子中,是否可以返回一个数组(字符串)?

Yuv*_*kov 7

在第二个例子中,它使用async和await,但是不返回任何类型的Task <>,为什么?

他们犯了一个错误.每当您创建一个异步且没有返回值的方法时,它应该返回一个Task.唯一的例外是事件处理程序,您需要保持与委托签名的兼容性,但事实并非如此.可以将a Task视为void异步方法的等价物.

为什么你真的想要回归Task而不是void?因为返回a Task允许您监视执行的状态,并且还允许您正确处理封装在正在进行的操作中的任何异常.

例如,想async void一下抛出的方法:

public async void WaitAndThrowAsync()
{
    await Task.Delay(1000);
    throw new Exception("yay");
}

public void CallWaitAndThrowAsync()
{
    // What happens when it throws here?
    WaitAndThrowAsync();
}
Run Code Online (Sandbox Code Playgroud)

当你调用它时,你无法真正处理方法中发生的异常,它对于调用站点来说是"一劳永逸".但是,当您公开a时Task,您现在可以通过异步等待来更好地处理该异常:

public async Task WaitAndThrowAsync()
{
    await Task.Delay(1000);
    throw new Exception("yay");
}

public async Task CallWaitAndThrowAsync()
{
    try
    {
        await WaitAndThrowAsync(); 
    }
    catch (Exception e)
    {
       // Do something. 
    }
}
Run Code Online (Sandbox Code Playgroud)

第三,在第一个例子中,是否可以返回一个数组(字符串)?

是的,通过返回Task<string[]>:

public async Task<string> GetArrayAsync()
{
    HttpClient client = new HttpClient();
    var responseStream = await client.GetStreamAsync("http://msdn.microsoft.com");

    using (var streamReader = new StreamReader(responseStream))
    {
        return await streamReader.ReadToEndAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

标记方法时async,编译器将隐式Task为您创建一个.当你有一个返回类型,所产生的任务是一个Task<T>地方T是你的返回类型.