【问题标题】:Why does calling Select() with a mapping function that internally awaits a Task return a list of Tasks instead of their results? [duplicate]为什么使用内部等待任务的映射函数调用 Select() 会返回任务列表而不是它们的结果? [复制]
【发布时间】:2018-05-04 21:34:17
【问题描述】:

所以我知道await 关键字将启动Task,暂停执行,然后在Task 完成后的某个时间点恢复执行并返回Task 的结果。

在下面的代码中,我使用 Select() 将用户 ID 列表映射到电子邮件地址列表。提供给Select() 的映射函数将创建并等待返回电子邮件地址的Task。因此执行将在映射函数内部暂停,然后再恢复,其中await 关键字将返回来自Task 的电子邮件地址,然后由映射函数返回。

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;

public class Program
{
    static void Main()
    {
        List<int> userIds = new List<int>{54, 24, 67};

        List<string> userEmails = userIds.Select
        (
            async userId => await GetUserEmailAsync(userId)
        );

        Console.WriteLine("Emails: " + String.Join(", ", userEmails.ToArray()));
    }

    private static Task<string> GetUserEmailAsync(int userId)
    {
        return new Task<string>(() => "user" + userId + "@gmail.com");
    }
}

但是,我收到一条错误消息,说明 Select() 调用返回的是 Tasks 列表,而不是字符串(电子邮件地址)。但是既然映射函数包含await并返回一个字符串,那么Select()调用不应该返回一个字符串列表吗?

【问题讨论】:

  • 请注意,第一句不正确 - await 不会启动任务。因此,如果您等待未启动的任务,例如在给定的代码中 - 它会永远等待(或直到您启动它)。
  • 哦,所以任务是在构造函数中启动的,就像 JavaScript 中的 Promises 一样?
  • 它是从 Start 方法开始的,但您几乎不需要这样做,也不需要使用构造函数创建任务。相反,您通常使用 Task.Run 和类似的构造,它们都返回已启动的任务。异步方法的结果也总是启动任务。

标签: c# .net linq async-await task


【解决方案1】:

那是因为async 方法总是返回TaskTask&lt;T&gt;。 所以如果你有async userId =&gt; await GetUserEmailAsinc(userId)。其实就是这个意思:

static async Task<string> MyFunction(string userId) {
    return await GetUserEmailAsync(userId);
}

在 C# 的当前版本 (7.*) 中,没有用于枚举/集合的 async/await 语法糖。它计划在下一个版本中发布,据我所知,蝙蝠仍然只是一个概念。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    相关资源
    最近更新 更多