如何让await任务数组(Task<T>[])变成事物数组(T[])?

How to get await an array οf tasks (Task<T>[]) to become an array of things (T[])?

这不是一般如何使用 asyncawait 的问题。它考虑了一个我在文档中没有找到的非常具体的案例。

我有一个我不习惯的类型设置。通常,我把 awaitTask<Whatever> 去任务化到它最终要有的类型。现在,我陷入了以下困境,经过一段时间的尝试,我意识到我不知道如何摆脱 output 中的 Task<Thing> 类型。我只希望它是 Thing

Task<Thing>[] output = list.Select(async a => new Thing
{
    Id = a.Id,
    Name = a.Name,
    Props = (await SomeService.GetAsync(a))
      .Select(b => b.Value).ToArray()
}).ToArray();

要求 output 的声明是显式的(即没有 var)并且不是异步的(即没有 Task)。 output 的类型必须是 Thing[],我不喜欢使用 Task.WhenAll(output),因为它需要提前声明 output,这违反了前两个要求。

需要内部 await 才能应用 Select。但这强加了外部async,因此使它成为事物任务的数组(即Task<Thing>[]),而不是事物数组(即Thing[])。

我不能将 await 放在列表前面,因为一组任务不可等待。我不能把它放在 lamba 表达式中,因为它破坏了语法。

我搜索了一些语法和示例,但这种情况有点不常见,所以我发现没什么价值。甚至可以做到吗?我相信它可以,但我不知道我们怎么做。我只找到了 this question。不过,它是相关的,但不够相似。而且答案实际上并没有显示如何实现我想要的(这是在变量声明中消除 varTask)。

我怀疑你在找 Task.WhenAll:

Thing[] result = await Task.WhenAll(output);

为了避免必须在任何地方使用 Task<Thing>[],或将长表达式作为 Task.WhenAll 的参数,您可以编写一个扩展方法:

public static class TaskEnumerable
{
    public static Task<T[]> WhenAllTasks<T>(this IEnumerable<Task<T>> tasks) =>
        Task.WhenAll(tasks);
}

您的代码可以是:

Thing[] output = await list.Select(async a => new Thing
{
    Id = a.Id,
    Name = a.Name,
    Props = (await SomeService.GetAsync(a))
      .Select(b => b.Value).ToArray()
}).WhenAllTasks();