Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<MyObject> does not contain a definition for GetAwaiter

Tags:

I have a method that returns a List<> of an object. This method takes a while to run.

private List<MyObject> GetBigList() {     ... slow stuff } 

This method is called from 4 or 5 sources. So, I thought I would try and use async and await to keep things moving while this list builds. I added this method:

public async Task<List<MyObject>> GetBigListAsync() {     var resultsTask = GetBigList();     var resuls = await resultsTask;     return resuls; } 

But, on this line:

var resuls = await resultsTask; 

I get this error:

List<MyObject> does not contain a definition for GetAwaiter, and no extension method 'GetAwaiter' accepting a first argument of type List<MyObject> could be found.

What am I missing?

like image 713
Casey Crookston Avatar asked Nov 23 '16 22:11

Casey Crookston


2 Answers

It seems you're a newbee to async-await. What really helped me to understand what async-await does is the restaurant analogy given by Eric Lippert in this interview. Search somewhere in the middle for async await.

Here he describes that if a cook has to wait for something, instead of doing nothing he starts looking around to see if he can do something else in the meantime.

Async-await is similar. Instead of awaiting for a file to be read, a database query to return, a web page to be downloaded, your thread will go up the callstack to see if any of the callers are not awaiting and performs those statements until he sees an await. Once he sees the await the thread goes up the call stack again to see if one of the callers is not awaiting etc. After a while when the file is read, or the query is finished etc, the statements after the await are performed.

Normally while reading your big list your thread would be very busy instead of idly waiting. It's not certain that ordering another thread to do the stuff would improve the time needed to read your list. Consider measuring both methods.

One reason to use async-await, even if it would lengthen the time needed to read the big list, would be to keep the caller (user interface?) responsive.

To make your function async, you should do the following:

  • Declare the function async;
  • Instead of TResult return Task<TResult> and instead of void return Task;
  • If your function calls other async functions, consider remembering the returned task instead of await, do other useful stuff you need to do and await the task when you need the result;
  • If you really want to let another thread do the busy stuff. call

    Task.Run( () => GetBigList())

and await when you need the results.

private async Task<List<MyObject>> GetBigListAsync() {     var myTask = Task.Run( () => GetBigList());     // your thread is free to do other useful stuff right nw     DoOtherUsefulStuff();     // after a while you need the result, await for myTask:     List<MyObject> result = await myTask;      // you can now use the results of loading:     ProcessResult(result);     return result; } 

Once again: if you have nothing useful to do while the other thread is loading the List (like keeping UI responsive), don't do this, or at least measure if you are faster.

Other articles that helped me understanding async-await were - Async await, by the ever so helpful Stephen Cleary, - and a bit more advanced: Async-Wait best practices.

like image 132
Harald Coppoolse Avatar answered Sep 23 '22 11:09

Harald Coppoolse


resultTask is just the list returned from GetBigList(), so nothing will happen async there.

What you can do is offload the task to a separate thread on the threadpool by using Task.Run and return the awaitable Task object:

// Bad code public Task<List<MyObject>> GetBigListAsync() {     return Task.Run(() => GetBigList()); } 

While above example best matches what you were trying to do, it is not best practice. Try to make the GetBigList() async by nature or if there really is no way, leave the decision about executing the code on a separate thread to the calling code and don't hide this in the implementation F.e. if the calling code already runs async, there is no reason to spawn yet another thread. This article describes this in more detail.

like image 33
huysentruitw Avatar answered Sep 19 '22 11:09

huysentruitw