为什么有些异步方法需要返回类型的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)。
为什么方法应该返回Task
或Task
?
每个返回的任务代表正在进行 任务封装有关异步进程状态的信息,并最终封装进程的最终结果或进程在未成功时引发的exception。
因此,当您使用void
时,您将丢失信息。 您丢弃实际的任务进度和执行信息。 因此,对于void
返回类型,请使用Task
。 对于任何其他类型,请使用Task
,其中T
是实际的返回类型。
有些方法可以返回void
,但是事件处理程序或入门方法禁止这样做:
异步方法也可以是Sub方法(Visual Basic)或具有void返回类型(C#)。 此返回类型主要用于定义事件处理程序,其中需要void返回类型。 异步事件处理程序通常用作异步程序的起点。