8

我有一个 .net core 3.1 控制台应用程序。

我有一个具有以下签名的方法:

public async IAsyncEnumerable<string> GetFilePathsFromRelativePathAsync(string relativePath)

如果我称之为:

private async Task<IEnumerable<FileUpload>> GetFileUploadsAsync(string relativePath)
{
...
    var filePaths = await service.GetFilePathsFromRelativePathAsync(relativePath);
...
}

我收到以下错误:

错误 CS1061“IAsyncEnumerable”不包含“GetAwaiter”的定义,并且找不到接受“IAsyncEnumerable”类型的第一个参数的可访问扩展方法“GetAwaiter”(您是否缺少 using 指令或程序集引用?)

4

1 回答 1

12

正确的语法是:

await foreach(var filePath in service.GetFilePathsFromRelativePathAsync(relativePath))
{
    ....
}

AnIAsyncEnumerable用于返回可以单独处理的元素流。这就是为什么该功能实际上被称为异步流,造成了相当多的混乱

转换为任务<IEnumerable<FileUpload>>

最好的解决方案是转换,而是将签名更改为IEnumerable<FileUpload>并在创建新FileUpload实例后立即返回:

private async IAsyncEnumerable<FileUpload> GetFileUploadsAsync(string relativePath)
{
    await foreach(var filePath in service.GetFilePathsFromRelativePathAsync(relativePath))
    {
        var upload = new FileUpload(filePath);
        yield return upload;
    }
}

您还可以收集所有结果,将它们存储在列表中并返回它们,例如使用ToListAsync扩展方法:

public static async Task<List<T>> ToListAsync<T>(this IAsyncEnumerable<T> source, CancellationToken cancellationToken=default)
{
    var list = new List<T>();
    await foreach (var item in source.WithCancellation(cancellationToken).ConfigureAwait(false))
    {
        list.Add(item);
    }

    return list;
}

最好的代码是你不写的代码。System.Linq.Async项目为 IAsyncEnumerable 提供 LINQ 运算符,包括ToList 并且可以在 NuGet上找到。

该代码非常简单,但包含一些优化,例如对来自其他运算符(如 GroupBy 和 Reverse)的数据使用ValueTask代替和特殊处理,这些运算符必须在产生输出之前消耗整个数据。TaskIAsyncEnumerable

于 2020-02-10T10:47:10.477 回答