简体   繁体   English

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

[英]How to use yield in async C# task

I am trying to you use yield and return a result from converting X into Y in an async task.我试图让你使用 yield 并返回在异步任务中将 X 转换为 Y 的结果。 But, I am getting an error on select.但是,我在选择时遇到错误。 The error is:错误是:

Error CS1942 The type of the expression in the select clause is incorrect.错误 CS1942 select 子句中的表达式类型不正确。 Type inference failed in the call to '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");
        });
    }

Short answer: you can't use an asynchronous yield statement.简短回答:您不能使用异步 yield 语句。

But in most cases, you don't need to.但在大多数情况下,您不需要。 Using LINQ you can aggregate all tasks before passing them into Task.WaitAll .使用LINQ您可以在将所有任务传递到Task.WaitAll之前聚合所有任务。 I simplified your example to return an IEnumberable<int> , but this will work with every type.我简化了您的示例以返回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)   ;
   }
}

Your example has another error await new Y(...) , a constructor cannot be asynchronous, therefore I replaced it with an asynchronous function.您的示例有另一个错误await new Y(...) ,构造函数不能是异步的,因此我用异步函数替换了它。 (As hinted in the comments, it is technically possible to create a custom awaitable type and create this type with new , although this is rarely used), (正如评论中所暗示的,在技术上可以创建自定义的可等待类型并使用new创建此类型,尽管很少使用),

The example above uses infos.Select to create a list of pending tasks, returned by invoking the function X .上面的示例使用infos.Select创建一个挂起任务列表,通过调用函数X返回。 This list of tasks will then be awaited and returned.然后将等待并返回此任务列表。

This workaround should fit most cases.workaround应适合大多数情况。 Real asynchronous iterators, as for example in JavaScript, are not supported in .Net. .Net 不支持真正的异步迭代器,例如在 JavaScript 中。

Update: This feature is currently suggested as a language proposal: Async Streams .更新:目前建议将此功能作为语言提案: Async Streams So maybe we will see this in the future.所以也许我们将来会看到这一点。

Update: If you need asynchronous iterators, there are a few options currently available:更新:如果您需要异步迭代器,目前有几个选项可用:

  1. Reactive Stream, RX.Net , which provides you with asynchronous observable streams based on events. Reactive Stream, RX.Net ,它为您提供基于事件的异步可观察流。
  2. There are implementations of asynchronous iterators or asynchronous enumerables AsyncEnumerable or .Net Async Enumerable有异步迭代器或异步可枚举的实现AsyncEnumerable.Net Async Enumerable

You do not.你不。 Async Enum support (and yield is there to implement enumerable) comes with C# 8 some point in 2019 as it looks. 2019 年的某个时间点,C# 8 提供了异步枚举支持(并且 yield 可以实现可枚举)。 So, for now the answer is simply that you do not.所以,现在的答案很简单,你没有。

The reason you get the error is that you can also not returna Result.您收到错误的原因是您也无法返回结果。 Yield (return) is specific to implementing enumerations.产量(回报)特定于实现枚举。 Your method signature does not match.您的方法签名不匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM