如何通过异步Task <string>方法的结果进行分组并在C#中按字符串进行分组?

时间:2019-05-13 09:00:19

标签: c# linq async-await

我有以下方法(这是扩展方法,但与该问题无关),我想在方法的结果上使用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>方法进行分组并按字符串进行分组?

2 个答案:

答案 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 => ...);

Full Demo here

注意 :您实际上没有任何可测试的代码,所以我只是提出了类似的内容

更新

您的示例不起作用的原因

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