【问题标题】:Async and await: Why doesn't an async method whose signature defines a return type of Task explicitly return a Task?异步和等待:为什么签名定义任务返回类型的异步方法不显式返回任务?
【发布时间】:2018-09-03 16:29:51
【问题描述】:

我用How to: Extend the async Walkthrough by Using Task.WhenAll (C#)开发了一个程序,可以独立异步提交多个数据库查询。该程序工作正常,但有一个细微差别我不明白,我找不到解释:

在示例中,方法SumPageSizesAsync 的签名是:

private async Task SumPageSizesAsync()

方法SumPageSizesAsync 的主体没有显式返回whenAllTask 对象(即WhenAll 汇总Task)。为什么SumPageSizesAsync 方法没有显式返回whenAllTask 任务? StartButton_Click 中调用SumPageSizesAsync 的代码行如何“知道”返回的是哪个任务?

private async void StartButton_Click(object sender, RoutedEventArgs e)
{
    .
    Task sumTask = SumPageSizesAsync();
    .
}


private async Task SumPageSizesAsync()
{
    HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1000000 };

    List<string> urlList = SetUpURLList();

    IEnumerable<Task<int>> downloadTasksQuery = from url in urlList select ProcessURLAsync(url);
    Task<int>[] downloadTasks = downloadTasksQuery.ToArray();

    Task<int[]> whenAllTask = Task.WhenAll(downloadTasks);

    int[] lengths = await whenAllTask;

    int total = lengths.Sum();

    // Display the total count for all of the web addresses.  
    resultsTextBox.Text += string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);

    // where's the return statement?
}

【问题讨论】:

  • 标记为异步的方法包装在 Task 对象中,无论您从它返回的是什么。这个问题的公认答案很好地解释了它:stackoverflow.com/questions/25191512/async-await-return-task
  • 谢谢,我并不是要争论,但这并不能完全回答我的问题。我了解wrapped in a Task 部分,但是编译器如何知道whenAllTask 任务是在没有显式编码分配的情况下要返回的任务?如果SumPageSizesAsync 方法有两个或更多Task.WhenAll 语句怎么办? (假设这是可能的)。
  • 您误解了它的工作原理。 whenAllTask 任务不是要返回的任务。方法的其余部分被编译器转换成一个Task,也就是要返回的Task。
  • @Dennis_E:“方法的其余部分作为任务返回”:哦,伙计,是的,当然。请将此作为答案发布。

标签: c# async-await task


【解决方案1】:

我完全同意 @Dennis_E 的回答,更多信息也可以在 C# 6 in a Nutshell 中找到(第 600 页)。

据作者介绍,在执行 async 函数时,返回类型为 task。如果方法体没有明确返回任务,则编译器创建一个任务

此任务随后用于以下目的,

  1. 方法的单选完成。
  2. 异步调用链。

【讨论】:

    【解决方案2】:

    为什么 SumPageSizesAsync 方法没有显式返回 whenAllTask​​ 任务?

    这不是该方法返回的任务。返回的任务是由编译器创建的。
    一旦遇到await,就会发生以下情况:
    - 如果whenAllTask 已经完成,则继续执行该方法的其余部分。
    - 否则,创建一个 Task 执行以下操作:
    1:等待whenAllTask完成。
    2:然后执行剩下的方法。
    然后立即返回此Task
    我一直认为return 语句嵌入在await 中。 “返回一个等待其他任务完成的任务,然后执行该方法的其余部分。”

    【讨论】:

      【解决方案3】:

      它是一个 async void 函数,意味着它返回 Task。既然已经在里面等待了,这里就没有什么不归路了。

      【讨论】:

      • 这个“它是一个异步 void 函数,意味着它返回任务”是没有意义的。要么是void,要么是returns,你不能两者兼得
      • 确切地说:async void 方法将具有签名:async void MyFunc()。我的方法的签名是async Task SumPageSizesAsync(),因此返回一个任务(正如 Dennis_E 教我的那样,任务是等待和 SumPageSizesAsync() 结束之间的 SumPageSizesAsync 中的代码(不包括等待)。有效/预期/有意义地使用async void 方法是调用进程的事件处理程序(按钮单击事件)。否则,async void 方法是由于未返回 Task 或 Task 而无法跟踪其结果的方法,即,有点没用。
      猜你喜欢
      • 2014-10-01
      • 2013-06-04
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2018-04-21
      • 1970-01-01
      • 2012-08-09
      相关资源
      最近更新 更多