【问题标题】:How to use yield in async C# task如何在异步 C# 任务中使用 yield
【发布时间】:2019-01-22 01:35:15
【问题描述】:

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

错误 CS1942 select 子句中的表达式类型是 不正确。调用“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"); });
  • 不确定yield 在这里的作用。而return await 只是添加了不必要的分层,如果这是方法中唯一的await
  • Y 也似乎是某种形式的等待,因为你awaiting 是构造一个的结果。我真的不知道你想在这里做什么。

标签: c# asynchronous task yield


【解决方案1】:

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

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

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(...),构造函数不能是异步的,因此我将其替换为异步函数。 (正如 cmets 中所暗示的,在技术上可以创建自定义等待类型并使用 new 创建此类型,尽管这很少使用),

上面的示例使用infos.Select 创建一个待处理任务列表,通过调用函数X 返回。然后将等待并返回此任务列表。

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

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

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

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

【讨论】:

  • await new Y(...) 不是必然错误。 Task 不是唯一可等待的,只是最常见的。 (话虽如此,OP 努力使 Y 可等待但仍然如此困惑的可能性很小)。
  • 你说得对,我会更新答案。但直到今天我还没有见过自定义等待者。
  • “通用异步返回类型”作为一种可能的语言特性不断重新出现,但我认为它还没有进入 C#。如果/当它们出现时,它可能会变得更常见。
  • @Damien_The_Unbeliever 目前没有语言功能,因此是提案的链接。但正如你所说,它不断浮出水面,所以它可能永远不会到来。
【解决方案2】:

你没有。看起来,C# 8 在 2019 年的某个时候提供了异步枚举支持(并且 yield 用于实现可枚举)。所以,现在的答案很简单,你不知道。

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

【讨论】:

  • 看起来他必须在这里结合async 和迭代器。他正在尝试使用迭代器来生成任务列表,然后等待它们全部完成。我认为yield 的使用具有误导性。
猜你喜欢
  • 2016-09-29
  • 2019-12-20
  • 2017-09-30
  • 1970-01-01
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多