How to "Await Yield Return Dosomethingasync()"

Is it possible to await yield return DoSomethingAsync()

What you are describing can be accomplished with the Task.WhenAll method. Notice how the code turns into a simple one-liner. What happens is that each individual url begins downloading and then WhenAll is used combine those operations into a single Task which can be awaited.

Task<IEnumerable<string>> DownLoadAllUrls(string[] urls)
{
return Task.WhenAll(from url in urls select DownloadHtmlAsync(url));
}

How and when to use ‘async’ and ‘await’

When using async and await the compiler generates a state machine in the background.

Here's an example on which I hope I can explain some of the high-level details that are going on:

public async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync can be done here

//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation
{
await Task.Delay(1000); // 1 second delay
return 1;
}

OK, so what happens here:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); starts executing LongRunningOperation

  2. Independent work is done on let's assume the Main Thread (Thread ID = 1) then await longRunningTask is reached.

    Now, if the longRunningTask hasn't finished and it is still running, MyMethodAsync() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningTask is done then a thread from the ThreadPool (can be any thread) will return to MyMethodAsync() in its previous context and continue execution (in this case printing the result to the console).

A second case would be that the longRunningTask has already finished its execution and the result is available. When reaching the await longRunningTask we already have the result so the code will continue executing on the very same thread. (in this case printing result to console). Of course this is not the case for the above example, where there's a Task.Delay(1000) involved.

async TaskIEnumerableT throws is not an iterator interface type error

Only methods declaring that they return IEnumerable<T>, IEnumerable, IEnumerator or IEnumerator<T> can be implemented with iterator blocks. That rules out all async methods.

Fundamentally it's not clear how they'd work anyway, given that IEnumerable<T> is pull-based, whereas asynchronous methods are more reactive. Also, the point of an iterator block is that callers can see intermediate results - whereas the task returned from an async method will not complete until the async method itself has completed.

You'll need to go for an alternative approach - whether that's Rx or something else. You might want to think first not about what the implementation will look like, but what the caller will do. Perhaps you actually want an IEnumerable<Task<List<T>>?

An entry point cannot be marked with the 'async' modifier

The error message is exactly right: the Main() method cannot be async, because when Main() returns, the application usually ends.

If you want to make a console application that uses async, a simple solution is to create an async version of Main() and synchronously Wait() on that from the real Main():

static void Main()
{
MainAsync().Wait();
}

static async Task MainAsync()
{
// your async code here
}

This is one of the rare cases where mixing await and Wait() is a good idea, you shouldn't usually do that.

Update: Async Main is supported in C# 7.1.

How can I make `await …` work with `yield return` (i.e. inside an iterator method)?

As of C# 8, this can be accomplished with IAsyncEnumerable

Modified code:

async IAsyncEnumerable<SomeClass> GetStuff()
{
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn)
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
SomeClass someClass = f(reader); // create instance based on returned row
yield return someClass;
}
}
}

Consume it like this:

await foreach (var stuff in GetStuff())
...

Error: return keyword must not be followed by an object expression in c# async code

Change your return type like this Task<List<photos>>

 public async Task<List<photos>> GetList()
{

List<Photos> photos = new List<Photos>();

if (photoIds != null)
{
foreach (int photoId in photoIds)
{
Photo photo = await ImageRepository.GetAsync(photoId);

if (photo != null)
photos.Add(photo);
}
}

return photos;
}

To call

var list = await GetList()


Related Topics



Leave a reply



Submit