LINQ 一直是 .NET 送给开发者最宝贵的礼物之一。它让数据查询如同魔法般简单——仅需少量代码即可完成集合的筛选、转换和聚合。
但在异步处理方面,始终存在一个痛点。虽然 IAsyncEnumerable<T> 早已存在,但要想实现任何实用功能,你必须从 NuGet 获取 System.Linq.Async。
是的,它能用,但这就像拥有一根只有向邻居借才能施展魔法的魔杖。
而现在,.NET 10 解决了这个问题——异步 LINQ 终于内置了,正式成为语言的一部分。
不再需要四处寻找包,不再有奇怪的兼容性问题,也不再担心“更新 NuGet 包会不会搞坏什么?”。
过去的痛点
在 .NET 10 之前,若要枚举 IAsyncEnumerable<T> 并执行任何 LINQ 操作,你必须引入 System.Linq.Async。这意味着 ToListAsync()、SelectAwait()、WhereAwait() 等所有好东西都存在于一个不属于核心语言的包中。你还得祈祷其他依赖项不会引入冲突的版本,否则你得花一下午调试“歧义方法错误”。真是“愉快”的时光。
var results = await e.SelectAwait(async (i, ct) => i * 2)
.ToListAsync(ct);
看起来没问题,对吧?但背后是一大堆 NuGet 包在支撑这段代码。它能用,但总感觉像是在潜在编译器错误的河流上踩着高跷行走。
.NET 10 的变革
.NET 10 将所有这些功能都移入了基础类库。AsyncEnumerable 现在成为标准配置。大多数情况下,你不再需要 System.Linq.Async。这太重要了——更少的包管理、更少的困惑,更多时间真正写代码,而不是谷歌“为什么 SelectAwait 有歧义?”。
你的大部分旧代码无需修改仍可运行。普通的 LINQ 查询(如 e.Select(i => i * 2))没问题,但某些调用点需要调整。
需要注意的迁移事项
System.Linq.Async,且计划迁移,直接删除它即可。System.Linq.AsyncEnumerable。System.Linq.Async 通过其他包间接引入,会出现歧义错误。以下是解决方法:<PackageReference Include="System.Linq.Async" Version="6.0.1">
<ExcludeAssets>compile</ExcludeAssets>
</PackageReference>
这样其他包可在内部使用它,但避免在你的代码中直接使用。若你确定运行时不需要它,可以更彻底:
<PackageReference Include="System.Linq.Async" Version="6.0.1">
<ExcludeAssets>all</ExcludeAssets>
</PackageReference>
最后,最让人头疼的一点:SelectAwait 消失了。在 .NET 10 中,异步 lambda 直接使用 Select。之前的代码片段变为:
var results = await e.Select(async (i, ct) => i * 2)
.ToListAsync(ct);
行为完全一致,只是代码中少了一个尴尬的额外单词——就像方法名瘦身了一样。
实战示例
假设你从 API 流式接收数字并翻倍。
之前(.NET 9 / System.Linq.Async):
var doubled = await numbers
.SelectAwait(async (n, ct) => n * 2)
.ToListAsync(ct);
之后(.NET 10):
var doubled = await numbers
.Select(async (n, ct) => n * 2)
.ToListAsync(ct);
结果相同,单词更少,无需额外的 NuGet 杂技。
为何重要
这一变化看似微小,实则影响深远:
深入探索
若你想深入了解,我已经对 IAsyncEnumerable 做了深度剖析,可在以下链接中找到:
深度解析:真实 .NET 应用中的 IAsyncEnumerable
异步流真正解决了什么、何时使用、为何大多数开发者误用它们。
blog.stackademic.com
真实 .NET 项目中的 IAsyncEnumerable:继续深入
从流式 API 到错误处理和取消,让异步流变得实用。
blog.stackademic.com
.NET 10 并非简单将 System.Linq.Async 复制到 BCL,而是让异步 LINQ 正式化、更清晰、更易用。大部分代码无需改动,少数调用点需微调,整体开发体验更顺畅。
如果你喜欢写更少的样板代码、管理更少的包、避免歧义方法错误,那么这正是一个能切实改善开发者日常工作的微小变革。