.net 核心 3.1:“IAsyncEnumerable<string>”不包含“GetAwaiter”的定义

Mur*_*ock 4 c# c#-8.0 iasyncenumerable .net-core-3.1

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

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

public async IAsyncEnumerable<string> GetFilePathsFromRelativePathAsync(string relativePath)
Run Code Online (Sandbox Code Playgroud)

如果我称之为:

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

我收到以下错误:

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

Pan*_*vos 10

正确的语法是:

await foreach(var filePath in service.GetFilePathsFromRelativePathAsync(relativePath))
{
    ....
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以收集所有结果,将它们存储在列表中并返回它们,例如使用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;
}
Run Code Online (Sandbox Code Playgroud)

最好的代码是你不写的代码。该System.Linq.Async项目提供LINQ运营商IAsyncEnumerable,包括ToList,可以发现上的NuGet

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