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

时间:2015-06-29 11:44:14

标签: c# asynchronous async-await task-parallel-library

在Microsoft的example中,该方法的返回类型为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;
}

在第二个例子中,它使用async和await,但是不返回任何类型的任务&lt;&gt;,为什么?

示例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);
            }
        }
    }
}

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

3 个答案:

答案 0 :(得分:7)

  

在第二个例子中,它使用async和await,但是不返回a   任务类型&lt;&gt;,为什么?

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

为什么您实际想要返回Task而不是void?因为返回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();
}

当你调用它时,你无法真正处理方法内部发生的异常,它会被激活并忘记&#34;对于呼叫站点。但是当您公开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. 
    }
}
  

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

是的,返回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();
    }
}

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

答案 1 :(得分:1)

第二个例子不是一个好例子:使用extension LAContext { func canEvaluatePolicyThrowing(policy: LAPolicy) throws { var error : NSError? canEvaluatePolicy(policy, error: &error) if let error = error { throw error } } } ,不可能等待异步方法。 async void仅应用于事件处理程序。

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

我真的建议您阅读Stephen Clearyhttps://msdn.microsoft.com/en-us/magazine/jj991977.aspx

中的这篇优秀文章

文章中的一些最佳做法:

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

答案 2 :(得分:0)

第二个不是根据guidelines specified by Microsoft

  

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

为什么方法应该返回TaskTask<T>

  

每个返回的任务代表正在进行的工作。任务封装有关异步进程状态的信息,最终是进程的最终结果,或者如果进程没有成功则进程引发的异常。

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

某些方法可以返回void,但这对事件处理程序或启动方法是禁止的:

  

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