You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中异步Lambda排序IEnumerable返回Task而非User的问题

异步Lambda在OrderByDescending中导致的类型错误问题

问题描述

我在为Discord机器人的小游戏制作排行榜时遇到问题。背景:我有一个小型的User对象集合users,想要获取其中'sushi'(一种分数)数量排名前10的用户。该sushi数据需从数据库单独获取(无需担心性能,数据库在本地SSD,用户集合已精简)。

我的代码如下:

IEnumerable<User> topUsers = users.OrderByDescending(async x => await FishEngine.GetItem(x, "sushi")).Take(10);

非异步方式下,按User对象本地存储的属性排序时一切正常,但使用上述异步代码后,foreach遍历topUsers时抛出异常,显示集合中不是User而是Task。

明明已经使用await,为何会出现这种情况?该如何解决?

PS:我知道通过SQL查询可以更快解决,但我希望理解异步Lambda的错误所在。

补充:GetItem方法代码:

public static async Task<int> GetItem(User dbUser, string name)
{
    return await UserEngine._interface.FetchInventoryItem(dbUser, name);
}

该方法在其他场景运行正常,无需深入探究内部实现。

错误原因

  • OrderByDescending不支持异步Lambda:当你给OrderByDescending传入异步Lambda时,这个Lambda的返回值是Task<int>,而非你期望的int。OrderByDescending会把Task<int>当作排序的键值,而不是等待Task完成后提取内部的int值,最终返回的集合类型实际是IOrderedEnumerable<Task<int>>,和你声明的IEnumerable<User>类型不匹配,遍历自然会出错。
  • Lambda内的await仅作用于内部调用:你在Lambda里写的await FishEngine.GetItem(...)只是让Lambda内部等待这个异步方法完成,但Lambda本身仍然是一个返回Task<int>的异步委托,OrderByDescending无法处理这种异步键值的生成逻辑。

解决方法

正确的做法是先批量获取所有用户的sushi分数并与User对象绑定,等待所有异步操作完成后再进行排序:

  1. 批量获取用户与对应sushi分数的配对集合:
var userSushiPairs = await Task.WhenAll(
    users.Select(async user => new { User = user, SushiCount = await FishEngine.GetItem(user, "sushi") })
);
  1. 对配对集合排序并提取前10个User对象:
IEnumerable<User> topUsers = userSushiPairs
    .OrderByDescending(pair => pair.SushiCount)
    .Take(10)
    .Select(pair => pair.User);

这个逻辑的核心是先用Task.WhenAll等待所有异步获取分数的操作完成,得到包含User和对应分数的完整数据集合,之后再用同步的排序方法处理,就能得到正确的User对象排行榜。

内容的提问来源于stack exchange,提问作者Markski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:41:16