Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert async lambda expression to delegate type System.Func<T>?

I have an async method inside a portable class library with this signature:

private async Task<T> _Fetch<T>(Uri uri) 

It fetches a resource that is cast back as a concrete type T.

I'm working with a 3rd party cache library (Akavache) that requires a Func<T> as one of the parameters and have tried to do so in this manner:

await this.CacheProvider.GetOrCreateObject<T>(key,     async () => await _Fetch<T>(uri), cacheExpiry); 

This results in the error:

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

I've tried various permutations of Func<T> assignment without any luck, the only way I can get the code to work is to make the Func<T> blocking:

await this.CacheProvider.GetOrCreateObject<T>(key,      () => _Fetch<T>(uri).Result, cacheExpiry);  

which deadlocks my app.

Any pointers on where I'm going astray?

like image 670
Craig Presti - MSFT Avatar asked Jun 21 '13 01:06

Craig Presti - MSFT


Video Answer


1 Answers

No can do. When someone expects a Func<T> f you can assume it will be invoked with something like result = f() - i.e., it does not know about async behavior. If you cheat it by using .Result like you have - it will deadlock on UI thread because it wants to schedule the code after await (in _Fetch) on the UI thread, but you have already blocked it with .Result.

Async lambda can be passed to Action since it has no return value - or to Func<Task> or Func<Task<T>>.

Looking at your case, the GetOrCreateObject appears to be calling GetOrFetchObject. One of the GetOrFetchObject overloads accepts a Func<Task<T>>. You can try calling that method with your async lambda and see if it helps.

like image 124
YK1 Avatar answered Sep 18 '22 06:09

YK1