4

I am trying to you use yield and return a result from converting X into Y in an async task. But, I am getting an error on select. The error is:

Error CS1942 The type of the expression in the select clause is incorrect. 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");
        });
    }
3
  • This part is weird: { yield return await new Y(info.Id, "Start"); }); Commented Aug 15, 2018 at 7:03
  • 2
    Not sure what the yield is meant to be doing here. And return await just adds unnecessary layering if that's the only await in a method. Commented Aug 15, 2018 at 7:05
  • 1
    And Y also appears to be some form of awaitable since you're awaiting the result of constructing one. I really have no idea what you're trying to do here. Commented Aug 15, 2018 at 7:07

2 Answers 2

6

Short answer: you can't use an asynchronous yield statement.

But in most cases, you don't need to. Using LINQ you can aggregate all tasks before passing them into Task.WaitAll. I simplified your example to return an IEnumerable<int>, but this will work with every type.

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. (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),

The example above uses infos.Select to create a list of pending tasks, returned by invoking the function X. This list of tasks will then be awaited and returned.

This workaround should fit most cases. Real asynchronous iterators, as for example in JavaScript, are not supported in .Net.

Update: This feature is currently suggested as a language proposal: 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.
  2. There are implementations of asynchronous iterators or asynchronous enumerables AsyncEnumerable or .Net Async Enumerable
Sign up to request clarification or add additional context in comments.

4 Comments

await new Y(...) is not necessarily an error. Task isn't the only awaitable, just the most common. (That being said, the chances that the OP has gone to the effort of making Y awaitable but is still this confused is minimal).
You are right, I will update the answer. But to this day I have never seen a custom awaiter.
"Generalized async return types" keeps resurfacing as a possible language feature but I don't think it's made it into C# yet. If/when they appear, it might become more common.
@Damien_The_Unbeliever it currently is no language feature, therefore the link to the proposal. But as you said, it keeps resurfacing, so it may never come.
3

You do not. Async Enum support (and yield is there to implement enumerable) comes with C# 8 some point in 2019 as it looks. 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.

1 Comment

It doesn't look like he has to combine async and iterators here. He's trying to use iterators to produce a list of tasks, and then wait for them all to complete. I think the use of yield is misleading.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.