如何在C#异步任务中使用yield

4

我正在尝试使用yield并从异步任务中返回将X转换为Y的结果。但是,在select上出现了错误。错误如下:

Error CS1942 选择子句中表达式的类型不正确。在调用“Select”时,类型推断失败。

public async Task<Result<dynamic>> GetYAsync(IEnumerable<X> infos)
    {
        return Task.WhenAll(from info in infos.ToArray() select async ()=>
        {
            yield return await new Y(info.Id, "Start");
        });
    }

这部分很奇怪:{ yield return await new Y(info.Id, "Start"); }); - Matěj Štágl
2
不确定这里的 yield 应该做什么。如果在方法中只有一个 await,那么 return await 只会增加不必要的层次。 - Damien_The_Unbeliever
1
而且 Y 似乎也是一种可等待的形式,因为您正在等待构造一个的结果。我真的不知道您在这里尝试做什么。 - Damien_The_Unbeliever
2个回答

5

简短回答:你不能使用异步yield语句。

但在大多数情况下,你不需要这样做。使用LINQ,你可以在将任务传递到Task.WaitAll之前聚合所有任务。我简化了你的示例以返回IEnumerable<int>,但这适用于每种类型。

public class Program
{
   public static Task<int> X(int x) 
   {
       return Task.FromResult(x);
   }
    
   public static async Task<IEnumerable<int>> GetYAsync(IEnumerable<int> infos)
   {
       var res = await Task.WhenAll(infos.Select(info => X(info)));
       return res;
   }
    
   public static async void Main()
   {
       var test = await GetYAsync(new [] {1, 2, 3});
       Console.WriteLine(test);
   }
}

您的示例存在另一个错误 await new Y(...),构造函数不能是异步的,因此我将其替换为异步函数。(正如评论中所提示的那样,技术上可以创建自定义可等待类型并使用new创建该类型,尽管这很少用到)。
上面的示例使用infos.Select创建一个由调用函数X返回的待处理任务列表。然后将等待并返回此任务列表。
这个“解决方法”适用于大多数情况。实际上,在.Net中不支持像JavaScript中那样的真正异步迭代器。
更新:目前建议将此功能作为语言提案:Async Streams。因此,也许我们将在未来看到这一点。
更新:如果您需要异步迭代器,目前有几个选项:
  1. 响应式流RX.Net,它为您提供基于事件的异步可观察流。
  2. 有异步迭代器或异步枚举的实现AsyncEnumerable.Net Async Enumerable

1
await new Y(...) 不一定是错误。 Task 不是唯一可等待的对象,只是最常见的。 (话虽如此,但 OP 已经将 Y 变成可等待对象,却仍然感到困惑的可能性很小)。 - Damien_The_Unbeliever
你说得对,我会更新答案。但直到今天我仍未见过自定义的awaiter。 - Iqon
“通用异步返回类型”一直被提出作为一种可能的语言特性,但我认为它还没有被纳入C#。如果它们出现了,它可能会变得更加普遍。 - Damien_The_Unbeliever
@Damien_The_Unbeliever 目前它不是一种语言特性,因此有提案的链接。但正如你所说,它一直在浮现,所以可能永远不会实现。 - Iqon

3

您不需要这样做。异步枚举支持(并且yield用于实现可枚举性)将随着C# 8在2019年某个时间点推出。因此,目前的答案很简单,您不需要这样做。

您收到错误的原因是,您也不能返回一个Result。Yield(return)是特定于实现枚举的。您的方法签名不匹配。


他似乎不必在这里结合“async”和迭代器。他试图使用迭代器生成任务列表,然后等待它们全部完成。我认为使用“yield”是具有误导性的。 - Rawling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接