如何将C# .NET 6中的IEnumerable方法转换为异步方法
将同步迭代器方法改造为异步方法(.NET 6)
1. 改造getUsersFor为异步迭代器方法
- 返回类型从
IEnumerable<User>改为IAsyncEnumerable<User>,这是.NET中异步迭代器的标准返回类型 - 方法名遵循异步命名规范改为
GetUsersForAsync - 添加
async修饰符 - 将原代码中阻塞线程的
.Result替换为await,适配异步调用逻辑 - 保留
yield return语法,异步迭代器原生支持该写法
改造后代码:
public async IAsyncEnumerable<User> GetUsersForAsync(string accountId) { ListUsersResponse usersResponse; string marker = null; do { using (var myClient = new ServiceClient(pass)) { usersResponse = await myClient.ListUsersAsync( new ListUsersRequest { Marker = marker, MaxItems = MAX_ITEMS }); foreach (var user in usersResponse.Users) { yield return user; } } marker = usersResponse.Marker; } while (usersResponse.IsTruncated); }
2. 改造getUsers为异步方法
- 返回类型改为
IAsyncEnumerable<MyUser>,方法名改为GetUsersAsync - 添加
async修饰符 - 由于同步LINQ的
SelectMany不支持异步枚举,提供两种实现方式:
方式一:手动遍历异步枚举(无需额外依赖)
通过await foreach逐个处理每个账号的用户集合,异常时跳过当前账号:
public async IAsyncEnumerable<MyUser> GetUsersAsync() { foreach (var accountId in AccountById.Keys) { try { await foreach (var user in GetUsersForAsync(accountId)) { yield return new MyUser(user, SetAccountUniqueName(AccountById[accountId].Name, AccountById[accountId].Id)); } } catch (Exception ex) { _log.Error(ex); } } }
方式二:使用LINQ Async扩展(需安装NuGet包)
若想保持类原LINQ的简洁写法,可安装System.Linq.Async NuGet包,使用异步LINQ扩展方法:
using System.Linq; public async IAsyncEnumerable<MyUser> GetUsersAsync() { return AccountById.Keys .SelectManyAsync(async accountId => { try { return await GetUsersForAsync(accountId) .Select(user => new MyUser(user, SetAccountUniqueName(AccountById[accountId].Name, AccountById[accountId].Id))) .ToListAsync(); } catch (Exception ex) { _log.Error(ex); return Enumerable.Empty<MyUser>(); } }); }
调用注意事项
异步迭代器方法需要用await foreach遍历结果,示例:
await foreach (var myUser in GetUsersAsync()) { // 处理用户逻辑 }
- 禁止在异步方法中使用
.Result或.Wait(),避免线程阻塞和死锁风险 - 添加
Async后缀是.NET异步方法的命名规范,提升代码可读性
内容的提问来源于stack exchange,提问作者Amir M
相关产品推荐
相关产品推荐

