2011-11-05 18 views
32

Estoy tratando de consumir una biblioteca C# en F #. La biblioteca hace un uso intensivo de async/await. Quiero usar dentro de un flujo de trabajo async { ... } en F #.Cómo Async.AwaitTask en Tarea simple (no Tarea <T>)?

veo podemos Async.AwaitTask en métodos asíncrono C# regresan Task<T>, pero ¿qué pasa con los que regresan llanura Task?

Tal vez, ¿hay un ayudante para convertir estos a Async<unit> o para convertir a TaskTask<unit> por lo que trabajará con Async.AwaitTask?

Respuesta

43

Puede utilizar ContinueWith:

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

O AwaitIAsyncResult con tiempo de espera infinito:

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

Ah, ya veo. Por supuesto, Task es un IAsyncResult después de todo. Acortado a 'let awaitTask = Async.AwaitIAsyncResult >> Async.Ignore' ¡Muchas gracias! – AshleyF

10

Me gustó mucho la sugerencia de Ashley usando la composición de funciones. Además, se puede ampliar el módulo asíncrono como esto:

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

Entonces aparece en Intellisense junto con Async.AwaitTask. Se puede usar así:

do! Task.Delay delay |> Async.AwaitTaskVoid 

¿Alguna sugerencia para un nombre mejor?

12

Actualización:

La biblioteca FSharp.Core para F # 4.0 ahora incluye una sobrecarga Async.AwaitTask que acepte una llanura Task. Si está usando F # 4.0, entonces debe usar esta función central en lugar del siguiente código.


Respuesta original:

Si su tarea podría lanzar una excepción, entonces probablemente también quieren comprobar esto. p.ej.

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

'raise task.Exception' solo aumentará la AggregateException; probablemente sea mejor acceder a su colección 'InnerExceptions' y subir la primera (siempre que la colección no esté vacía) –

1

se propaguen correctamente ambas excepciones y cancelación de forma adecuada, lo que se necesita algo como esto (basado parcialmente en respuesta borrado 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)