【问题标题】:Accessing the return value of Task on the same line as await与 await 在同一行访问 Task 的返回值
【发布时间】:2025-12-01 06:55:02
【问题描述】:

我有一个方法 SplitInto2DArray,它将表示 CSV 文件的 File 对象转换为 File2DArray 类。

File2DArray 是一个简单的类,其中包含一个用于标题的数组和一个用于正文的二维数组。

public class File2DArray
{
    public string[] Headers;
    public string[][] Content;
}

为了将 File 对象数组转换为 File2DArray 对象,我做了: Files.Select(File => File.SplitInto2DArray().Content

但是,我将 SplitInto2DArray 变成了一个异步函数,因为它阻塞了带有大量大型 CSV 文件的线程。 当我这样做时,我不得不更改 Select 函数,但我遇到了问题。

.Select(async File => await File.SplitInto2DArray().Content

SplitInto2DArray 不再返回File2DArray,而是返回不具有Content 属性的Task<File2DArray>

我可以将其转换为多行 lambda,但我很感兴趣是否有一种方法可以访问与 await 在同一行上的 await Task<T> 的输出。

【问题讨论】:

  • 这完全是猜测,但你能做到(await File.SplitInto2DArray()).Content吗? await 必须在获取内容之前发生。
  • Dot 的优先级高于 await,所以你只需要额外的括号。 (await File.SplitInto2DArray()).Content
  • @RaymondChen @Xtros 我查看了这个以响应@Messenger 的回答并在await Task<File2DArray> 周围添加括号似乎将lambda 函数的返回类型更改为Task<string[][]> 而不是@987654335 @ 这很奇怪,我不知道为什么会这样。
  • 我看到将 lambda 声明为 async 导致 Select() 返回 IEnumerable<Task<T>> 而不是 IEnumerable<T>。但是,它需要返回IEnumerable<T>,并且使用另一个Selectasync Task => await Task 将返回另一个IEnumerable<Task<T>> 而不是IEnumerable<T>。有没有办法获取值列表而不是任务?

标签: c# asynchronous


【解决方案1】:

试试Files.Select(async File => (await File.SplitInto2DArray()).Content)

有一对括号包含await File.SplitInto2DArray()

虽然await 关键字会阻塞当前线程,直到异步函数完成并返回,但Task<File2DArray> 变为File2DArray

也许这不是一个准确的解释,但它应该有效。

【讨论】:

  • Files.Select(async File => (await File.SplitInto2DArray()).Content) 返回类型 IEnumerable<Task<string[][]>> 而不是 IEnumerable<string[][]>。这可能是因为 .Content 被评估为 Task<T>? 的一部分。我不确定。
  • “虽然 await 关键字会阻塞当前线程,直到异步函数完成并返回” - 这是不准确的。在异步函数完成之前,该方法的其余部分不会运行,但线程不会被阻塞。
【解决方案2】:

您可以使用System.Linq.Async nuget 包为IAsyncEnumerable 获得不错的扩展

PM> Install-Package System.Linq.Async

你的代码看起来像

var contents = await Files.ToAsyncEnumerable()
    .SelectAwait(async file => await file.SplitInto2DArray())
    .Select(array => array.Content)
    .ToListAsync();

【讨论】:

    最近更新 更多