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

Ayd*_*may 5 c# asynchronous yield task

我试图使用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");
        });
    }
Run Code Online (Sandbox Code Playgroud)

Iqo*_*qon 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)   ;
   }
}
Run Code Online (Sandbox Code Playgroud)

您的示例有另一个错误await new Y(...),构造函数不能是异步的,因此我用异步函数替换它.(正如评论中所暗示的那样,技术上可以创建自定义等待类型并创建此类型new,尽管很少使用),

上面的示例infos.Select用于创建通过调用函数返回的挂起任务列表X.然后将等待并返回此任务列表.

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

更新:此功能目前建议用作语言提议:Async Streams.所以也许我们将来会看到这一点.

更新:如果您需要异步迭代器,目前有几个选项:

  1. Reactive Stream,RX.Net,它根据事件为您提供异步可观察流.
  2. 有异步迭代器或异步可枚举的实现AsyncEnumerable.Net Async Enumerable