我有以下方法(这是扩展方法,但与该问题无关),我想在方法的结果上使用GroupBy
。
class MyClass
{
public async Task<string> GetRank()
{
return "X";
}
public async static Task Test()
{
List<MyClass> items = new List<MyClass>() { new MyClass() };
var grouped = items.GroupBy(async _ => (await _.GetRank()));
}
}
grouped
的类型为IGrouping<Task<string>, MyClass>
,但是我需要根据异步方法(字符串)的实际等待结果进行分组。尽管使用了await并使lambda异步,但我仍然得到IGrouping<Task<string>, ..>
而不是IGrouping<string, ...>
如何使用GroupBy并通过异步Task<string>
方法进行分组并按字符串进行分组?
答案 0 :(得分:2)
您可能正在寻找首先await
所有任务,然后是 group
// projection to task
var tasks = items.Select(y => AsyncMethod(y);
// Await them all
var results = await Task.WhenAll(tasks)
// group stuff
var groups = results.GroupBy(x => ...);
注意 :您实际上没有任何可测试的代码,所以我只是提出了类似的内容
更新
您的示例不起作用的原因
items.GroupBy(async _ => (await _.GetRank()))
是因为async
和lambda实际上只是一个返回任务的方法,这就是为什么您得到IGrouping<Task<string>, MyClass>
您需要先等待所有任务完成,然后才能考虑对任务的结果做任何事情
要进一步说明正在发生的事情,请看一下SharpLab example
您的async
lambda 基本上解决了此问题
new Func<int, Task<string>>(<>c__DisplayClass1_.<M>b__0)
答案 1 :(得分:0)
这是GroupBy
的异步版本。它期望任务keySelector
的结果,并返回可以等待的任务:
public static async Task<IEnumerable<IGrouping<TKey, TSource>>>
GroupByAsync<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, Task<TKey>> keySelector)
{
var tasks = source.Select(async item => (Key: await keySelector(item), Item: item));
var entries = await Task.WhenAll(tasks);
return entries.GroupBy(entry => entry.Key, entry => entry.Item);
}
可以这样使用:
class MyClass
{
public async Task<string> GetRank()
{
await Task.Delay(100);
return "X";
}
public async static Task Test()
{
var items = new List<MyClass>() { new MyClass(), new MyClass() };
var grouped = items.GroupByAsync(async _ => (await _.GetRank()));
foreach (var grouping in await grouped)
{
Console.WriteLine($"Key: {grouping.Key}, Count: {grouping.Count()}");
}
}
}
输出:
键:X,计数:2