J'ai une méthode asynchrone dans une bibliothèque de classes portable avec cette signature:
private async Task<T> _Fetch<T>(Uri uri)
Il récupère une ressource qui est rejetée en tant que type concret T.
Je travaille avec une bibliothèque de cache tierce ( Akavache ) qui nécessite un Func<T>
comme l'un des paramètres et a essayé de le faire de cette manière:
await this.CacheProvider.GetOrCreateObject<T>(key,
async () => await _Fetch<T>(uri), cacheExpiry);
Cela se traduit par l'erreur:
Impossible de convertir l'expression lambda asynchrone en type de délégué '
System.Func<T>
'. Une expression lambda asynchrone peut renvoyervoid
,Task
ouTask<T>
, dont aucun n'est convertible en 'System.Func<T>
'.
J'ai essayé différentes permutations de Func<T>
affectation sans aucune chance, la seule façon de faire fonctionner le code est de faire le Func<T>
blocage:
await this.CacheProvider.GetOrCreateObject<T>(key,
() => _Fetch<T>(uri).Result, cacheExpiry);
qui bloque mon application.
Des conseils sur où je m'égare?
Ne peut faire. Lorsque quelqu'un attend un Func<T> f
, Vous pouvez supposer qu'il sera invoqué avec quelque chose comme result = f()
- c'est-à-dire qu'il ne connaît pas le comportement asynchrone. Si vous le trichez en utilisant .Result
Comme vous l'avez fait - il se bloquera sur le thread d'interface utilisateur car il veut planifier le code après await
(dans _Fetch) sur le thread d'interface utilisateur, mais vous avez déjà bloqué avec .Result
.
Lambda asynchrone peut être passé à Action
car il n'a pas de valeur de retour - ou à Func<Task>
Ou Func<Task<T>>
.
En regardant votre cas, le GetOrCreateObject
semble appeler GetOrFetchObject
. L'une des surcharges GetOrFetchObject
accepte un Func<Task<T>>
. Vous pouvez essayer d'appeler cette méthode avec votre lambda asynchrone et voir si cela aide.
réponse de YK1 explique pourquoi vous ne pouvez pas traiter Func<T>
asynchrone.
Pour résoudre votre problème, utilisez GetOrFetchObject
au lieu de GetOrCreateObject
. Les méthodes "create" supposent une création (synchrone), tandis que les méthodes "fetch" fonctionnent avec la récupération (asynchrone).
await CacheProvider.GetOrFetchObject<T>(key, () => _Fetch<T>(uri), cacheExpiry)
J'ai également supprimé le async
/await
inutile dans votre expression lambda. Puisque _Fetch
renvoie déjà Task<T>
, il n'est pas nécessaire de créer un async
lambda dont le seul but est de await
cette tâche.