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

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

例1:

 async Task AccessTheWebAsync() { // You need to add a reference to System.Net.Http to declare client. HttpClient client = new HttpClient(); // GetStringAsync returns a Task. That means that when you await the // task you'll get a string (urlContents). Task 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; } 

在第二个例子中,它使用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); } } } } 

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

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

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

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

例如,考虑抛出的async void方法:

 public async void WaitAndThrowAsync() { await Task.Delay(1000); throw new Exception("yay"); } public void CallWaitAndThrowAsync() { // What happens when it throws here? WaitAndThrowAsync(); } 

当你调用它时,你无法实际处理方法中发生的exception,它对于呼叫站点来说是“一劳永逸”。 但是当您公开Task ,您现在可以通过异步等待来更好地处理该exception:

 public async Task WaitAndThrowAsync() { await Task.Delay(1000); throw new Exception("yay"); } public async Task CallWaitAndThrowAsync() { try { await WaitAndThrowAsync(); } catch (Exception e) { // Do something. } } 

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

是的,通过返回Task

 public async Task GetArrayAsync() { HttpClient client = new HttpClient(); var responseStream = await client.GetStreamAsync("http://msdn.microsoft.com"); using (var streamReader = new StreamReader(responseStream)) { return await streamReader.ReadToEndAsync(); } } 

将方法标记为async ,编译器将隐式为您创建Task 。 当您有返回类型时,生成的任务是Task ,其中T是您的返回类型。

第二个例子不是一个很好的例子:使用async void它不再可能等待异步方法。 async void仅应用于事件处理程序。

对于你的第二个问题,是的,它可以返回一个字符串数组。 只需使用Task

我真的建议你阅读Stephen Cleary的这篇优秀文章: https : //msdn.microsoft.com/en-us/magazine/jj991977.aspx

文章中的一些最佳实践:

  • 避免异步void:首选async任务方法优于异步void方法 。 例外:事件处理程序
  • 一直异步:不要混合阻塞和异步代码。 例外:控制台主要方法

第二个不符合Microsoft指定的准则 :

返回类型是以下类型之一: – 如果您的方法具有返回语句,其中操作数的类型为TResult,则为任务。 – 如果您的方法没有return语句或者没有操作数的return语句,则执行任务。 – 如果您正在编写异步事件处理程序,则为Void(Visual Basic中的Sub)。

为什么方法应该返回TaskTask

每个返回的任务代表正在进行 任务封装有关异步进程状态的信息,并最终封装进程的最终结果或进程在未成功时引发的exception。

因此,当您使用void时,您将丢失信息。 您丢弃实际的任务进度和执行信息。 因此,对于void返回类型,请使用Task 。 对于任何其他类型,请使用Task ,其中T是实际的返回类型。

有些方法可以返回void ,但是事件处理程序或入门方法禁止这样做:

异步方法也可以是Sub方法(Visual Basic)或具有void返回类型(C#)。 此返回类型主要用于定义事件处理程序,其中需要void返回类型。 异步事件处理程序通常用作异步程序的起点。