2013-06-21 2 views
18

Ich habe eine Asynchron-Methode in einem tragbaren Klassenbibliothek mit dieser Signatur:Konvertieren asynchronen Lambda-Ausdruck in Delegate-Typ System.Func <T>?

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

Es eine Ressource abruft, die als konkreten T. zurückgeworfen wird

ich mit einer 3rd-Party-Cache arbeiten Bibliothek (Akavache), die ein Func<T> als einer der Parameter und haben versucht, so erfordert auf diese Weise zu tun:

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

Dies führt im Fehler:

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> '.

ich verschiedene Permutationen von Func<T> Zuordnung ohne Erfolg versucht haben, die einzige Möglichkeit, den Code an die Arbeit bekommen kann, ist die Func<T> Blockierung zu machen:

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

, die meine app Deadlocks.

Irgendwelche Hinweise darauf, wo ich in die Irre gehe?

+0

Sie suchen nach 'Func ' –

Antwort

13

Nein kann. Wenn jemand einen Func<T> f erwartet, können Sie annehmen, dass er mit etwas wie result = f() aufgerufen wird - d. H. Er weiß nichts über asynchrones Verhalten. Wenn Sie es mit .Result wie Sie cheat - es wird Deadlock auf UI-Thread, weil es den Code nach await (in _Fetch) auf dem UI-Thread planen möchten, aber Sie haben bereits blockiert mit .Result.

Asynchrones Lambda kann an Action übergeben werden, da es keinen Rückgabewert hat - oder an Func<Task> oder Func<Task<T>>.

Mit Blick auf Ihren Fall scheint die GetOrCreateObjectGetOrFetchObject aufrufen. Eine der GetOrFetchObject Überladungen akzeptiert eine Func<Task<T>>. Sie können versuchen, diese Methode mit Ihrem asynchronen Lambda aufzurufen und zu sehen, ob es hilft.

+3

Ich möchte betonen, dass, wenn eine Methode akzeptiert eine 'Aktion' und Sie es eine' async' Lambda übergeben, dann ist das die falsche Sache zu tun, die meiste Zeit. – svick

+0

@svick: Ja stimme mit Ihnen überein. Genau wie die Methode, die 'Func ' akzeptiert, weiß die Methode, die eine 'Aktion' akzeptiert, nicht über ihr asynchrones Verhalten.Async-Lambda, die kein Ergebnis liefert, würde idealerweise an 'Func ' übergeben. Es ist nur so, dass der C# -Compiler es an 'Action' übergeben kann, weil es keinen Rückgabewert gibt. – YK1

+0

Danke YK1, ich fühle mich jetzt ziemlich albern - ich hatte eine Schnittstelle implementiert, um den Cache-Provider wegzuspulen und die alternative Methode in der Basisbibliothek zu verpassen. –

-3

So ähnlich?

Public Func<T> ConvertTask<T>(Task<T> task) 
{ 
    return()=>task.Result; 
} 
+0

Die Frage besagt eindeutig, dass die Verwendung von "Result" einen Deadlock verursacht. – svick

4

YK1's answer erklärt, warum Sie nicht Func<T> als asynchrone behandeln kann.

Um das Problem zu beheben, verwenden Sie GetOrFetchObject anstelle von GetOrCreateObject. Die "create" -Methoden setzen eine (synchrone) Erstellung voraus, während die "fetch" -Methoden mit (asynchronem) retrieval arbeiten.

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

Ich entfernte auch die unnötige async/await in Ihrem Lambda-Ausdruck. Da _Fetch bereits Task<T> zurückgibt, ist es nicht notwendig, einen async Lambda zu erstellen, dessen einziger Zweck es ist, diese Aufgabe zu await.

+0

Danke Stephen, genau so habe ich das Problem gelöst. –

Verwandte Themen