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

时间:2018-08-15 06:56:35

标签: c# asynchronous task yield

我正在尝试使用yield并在异步任务中返回将X转换为Y的结果。但是,我在选择时遇到错误。 错误是:

  

错误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");
        });
    }

2 个答案:

答案 0 :(得分:6)

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

但是在大​​多数情况下,您不需要这样做。使用LINQ,您可以先汇总所有任务,然后再将其传递到Task.WaitAll。我简化了您的示例以返回IEnumberable<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返回的。然后将等待并返回此任务列表。

workaround应该适合大多数情况。 .Net不支持真正的异步迭代器,例如JavaScript。

更新:当前建议将此功能作为语言建议:Async Streams。因此,也许将来我们会看到这种情况。

更新:如果您需要异步迭代器,则当前有一些可用选项:

  1. 反应性流RX.Net,可为您提供基于事件的异步可观察流。
  2. 存在异步迭代器或异步枚举AsyncEnumerable.Net Async Enumerable

答案 1 :(得分:3)

您没有。看起来C#8在2019年的某个时候附带了异步枚举支持(并且可以实现可枚举的收益率)。因此,目前的答案很简单,就是您不知道。

出现错误的原因是您也无法返回结果。收益(回报)特定于实现枚举。您的方法签名不匹配。