2011-11-05 6 views
32

Sto provando a consumare una libreria C# in F #. La libreria usa pesantemente async/await. Voglio utilizzare all'interno di un flusso di lavoro async { ... } in F #.Come eseguire Async.AwaitTask su semplice attività (non Attività <T>)?

vedo possiamo Async.AwaitTask sul asincrona C# i metodi di ritorno Task<T>, ma che dire di coloro che ritornano pianura Task?

Forse, c'è un aiuto per convertire questi per Async<unit> o per convertire Task-Task<unit> in modo che possa funzionare con Async.AwaitTask?

risposta

43

È possibile utilizzare ContinueWith:

let awaitTask (t: Task) = t.ContinueWith (fun t ->()) |> Async.AwaitTask 

O AwaitIAsyncResult con timeout infinito:

let awaitTask (t: Task) = t |> Async.AwaitIAsyncResult |> Async.Ignore 
+10

Ah, capisco. Naturalmente, Task è un IAsyncResult dopo tutto. Abbreviato in 'let awaitTask = Async.AwaitIAsyncResult >> Async.Ignore' Grazie mille! – AshleyF

10

Mi è piaciuto molto il suggerimento di Ashley utilizzando la funzione di composizione. Inoltre, è possibile estendere il modulo di Async in questo modo:

module Async = 
    let AwaitTaskVoid : (Task -> Async<unit>) = 
     Async.AwaitIAsyncResult >> Async.Ignore 

poi appare in Intellisense insieme Async.AwaitTask. Può essere utilizzato in questo modo:

do! Task.Delay delay |> Async.AwaitTaskVoid 

Qualche suggerimento per un nome migliore?

12

Aggiornamento:

La biblioteca FSharp.Core per F # 4.0 ora include un Async.AwaitTask overload che accetta una pianura Task. Se stai usando F # 4.0, dovresti usare questa funzione principale al posto del codice qui sotto.


risposta originale:

Se il vostro compito potrebbe generare un'eccezione, allora probabilmente anche voler controllare per questo. per esempio.

let awaitTask (task : Task) = 
    async { 
     do! task |> Async.AwaitIAsyncResult |> Async.Ignore 
     if task.IsFaulted then raise task.Exception 
     return() 
    } 
+0

'raise task.Exception 'solleverà AggregateException; probabilmente è meglio accedere alla sua raccolta 'InnerExceptions' e alzare la prima (purché la raccolta non sia vuota) –

1

per propagare correttamente entrambe le eccezioni e cancellazione correttamente, io penso avete bisogno di qualcosa di simile (in parte in base alla risposta cancellato dallo Tomáš Petříček):

module Async = 
    let AwaitVoidTask (task : Task) : Async<unit> = 
     Async.FromContinuations(fun (cont, econt, ccont) -> 
      task.ContinueWith(fun task -> 
       if task.IsFaulted then econt task.Exception 
       elif task.IsCanceled then ccont (OperationCanceledException()) 
       else cont()) |> ignore) 
Problemi correlati