15

I would want to call an async method inside lambda expression. Please help me doing the below

eg -

return xyz.Where(async x=> await AsyncMethodCall(x.val)); 

And the Async method looks like

public async Task<bool> AsyncMethodCall(Data d){...} 

When I do the above, I get the following error

Error CS4010 Cannot convert async lambda expression to delegate type 'Func<Data, bool>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<Data, bool>'.

Thanks in advance for the help

7
  • Where is a filter. It's supposed to filter things, not make random changes. Why are you using an asynchronous method in it? Are you using it as if it were a Select statement? Commented May 11, 2017 at 13:44
  • 2
    @PanagiotisKanavos For example it could call a web service, or access a DB... The question is good... You can't do it, and even if you could it wouldn't probably be a good idea, but that is another problem... Commented May 11, 2017 at 13:46
  • 2
    @xanatos the fact it's a bad idea is probably why you can't do it, ie why there is no Where() method that accepts a Task Commented May 11, 2017 at 13:46
  • In general async and IEnumerable<> don't mix, because Task (the class at the base of async) presuppose that the result it contains can be used only when it is Completed... but here you have that the pieces of the result (the single xyz elements) can be enumerated "during" the lifetime of the Task, and the Task is Completed when there are no more elements. Commented May 11, 2017 at 13:53
  • Your async and await cancel each other out. The same but simpler: .Where(x => AsyncMethodCall(x.val)). This should give you the same error, the Where() extensions method doesn't accept awaitables. Commented May 11, 2017 at 13:54

1 Answer 1

20

Asynchronous sequences are tricky because you really have to think about what specifically you want the code to do.

For example, you could want to execute the AsyncMethodCall calls sequentially, and then return all the results:

var result = new List<T>(); foreach (var d in xyz) if (await AsyncMethodCall(d.val)) result.Add(d); return result; 

Or, you could execute all the AsyncMethodCall calls concurrently, and then collect and return the results (again, all at once):

var tasks = xyz.Select(async d => new { d, filter = await AsyncMethodCall(d.val) }); var results = await Task.WhenAll(tasks); return results.Where(x => x.filter).Select(x => x.d); 

Or, you could execute all the AsyncMethodCall calls sequentially, and produce the results one at a time. This approach is incompatible with IEnumerable<T> (assuming you want to keep the call asynchronous). If you want to produce a sequence where AsyncMethodCall is asynchronously invoked during sequence enumeration, then you would need to change to IAsyncEnumerable<T>. If you want to produce a sequence that is started by the consumer and then produces results on its own, you would need to change to IObservable<T>.

Or, you could execute all the AsyncMethodCall calls concurrently, and produce the results one at a time. This is also incompatible with IEnumerable<T>; you would need to change to IObservable<T>. And you would also need to decide whether to maintain the original ordering, or to produce them in order of AsyncMethodCall completing.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.