将IAsyncEnumerable转换为List

111

C#8中,我们新增了IAsyncEnumerable接口。

如果我们有一个普通的IEnumerable,我们可以使用Linq将其转换为List或任何其他我们想要的集合。

var range = Enumerable.Range(0, 100);
var list = range.ToList();

现在我想将我的IAsyncEnumerable转换为List,当然需要异步操作。是否已经有了适用于这种情况的Linq实现? 如果没有,我该如何自己进行转换呢?

2个回答

181

当然可以 - 你只需要使用ToListAsync()方法,它在System.Linq.Async NuGet包中。下面是完整的示例:

项目文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Linq.Async" Version="4.0.0" />
  </ItemGroup>

</Project>

代码:

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

class Program
{
    static async Task Main(string[] args)
    {
        IAsyncEnumerable<string> sequence = GetStringsAsync();
        List<string> list = await sequence.ToListAsync();
        Console.WriteLine(list.Count);
    }

    static async IAsyncEnumerable<string> GetStringsAsync()
    {
        yield return "first";
        await Task.Delay(1000);
        yield return "second";
        await Task.Delay(1000);
        yield return "third";
    }
}

4
谢谢您的留言,有趣的是它还没有成为 .Net Core 3.1 Framework 的一部分。 - Twenty
6
作为一个独立的软件包,它可以轻松地在许多老旧平台上使用。 - Jon Skeet
2
@ca9163d9: "它出现了错误" 并没有提供太多信息。我建议您使用完整的 [mcve] 提出一个新问题。 - Jon Skeet
2
正如我之前所说,请提出一个完整的示例来询问新问题 - 并且请将错误描述得更清楚,而不是仅仅说“它失败了”。 - Jon Skeet
1
@db2:是的,你需要更具体地描述问题,我才能帮助你。我建议你提出一个带有 [mcve] 的新问题。 - Jon Skeet
显示剩余6条评论

25

如果您不想引入 NuGet 包,这里是(可能与包中提到的类似的)扩展方法:

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

2
https://github.com/dotnet/reactive/blob/7fe854ff18e8bbf2548bc18cd1dd5019a923e34a/Ix.NET/Source/System.Linq.Async/System/Linq/Operators/ToList.cs#L32 - Ian Kemp
4
@Andrew Williamson 这在最近的提交中已被更改。原因是出于性能方面的考虑。现在它会对参数进行一些验证。你会注意到外部函数没有标记为 async,只有本地函数是。因此,如果验证失败,我们将不会浪费时间设置异步状态机。 - Jamie Twells
为什么不想使用NuGet包呢?它不是那些“可疑”的包之一,而是由dotnetfoundation支持的包。 - Jonas Stensved
6
因为可能与 EF Core 发生冲突,所以如果一起使用,@JonasStensved建议不要使用。我目前在代码中只使用了一次 ToListAsync,如果我添加这个 Nuget 包,会出现很多歧义错误,因为 EF Core 是同一项目的依赖项。 - El Mac
请注意,这将强制按顺序运行任务。(在进行第二个任务之前必须等待第一个任务完成)。这可能是您想要的,但也可能会导致死锁(如果您希望它们像Task.WhenAll一样并行运行,并且第二个任务依赖于第一个任务)。 - Mike S
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接