37

我在具有此签名的可移植类库中有一个异步方法:

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

它获取一个作为具体类型 T 回退的资源。

我正在使用需要 a作为参数之一的第 3 方缓存库 ( AkavacheFunc<T> ),并尝试以这种方式这样做:

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

这会导致错误:

无法将异步 lambda 表达式转换为委托类型“ System.Func<T>”。异步 lambda 表达式可能返回或void,它们都不能转换为 ' '。TaskTask<T>System.Func<T>

我已经尝试了各种Func<T>分配排列但没有任何运气,我可以让代码工作的唯一方法是进行Func<T>阻塞:

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

这使我的应用程序陷入僵局。

关于我会误入歧途的任何指示?

4

2 回答 2

31

没办法。当有人期望 a 时Func<T> f,您可以假设它将被调用,例如 result = f()- 即,它不知道异步行为。如果你.Result像以前一样使用它来欺骗它 - 它会在 UI 线程上死锁,因为它想在 UI 线程await上(在 _Fetch 中)安排代码,但你已经用.Result.

可以将异步 lambda 传递给,Action因为它没有返回值 - or to Func<Task>or Func<Task<T>>

查看您的案例,GetOrCreateObject似乎正在调用GetOrFetchObject. 其中一个GetOrFetchObject重载接受Func<Task<T>>. 您可以尝试使用异步 lambda 调用该方法,看看是否有帮助。

于 2013-06-21T04:56:35.323 回答
7

YK1 的回答解释了为什么您不能将Func<T>其视为异步。

要解决您的问题,请使用GetOrFetchObject而不是GetOrCreateObject. “create”方法假定(同步)创建,而“fetch”方法与(异步)检索一起工作。

await CacheProvider.GetOrFetchObject<T>(key, () => _Fetch<T>(uri), cacheExpiry)

我还删除了您的 lambda 表达式中不必要的async/ await。由于_Fetch已经返回Task<T>,因此无需创建async其唯一目的是完成await该任务的 lambda。

于 2013-06-21T12:27:50.987 回答