2011-11-05 20 views
32

Próbuję spożywać biblioteki C# w F #. Biblioteka intensywnie korzysta z asynchronizacji/oczekiwania. Chcę użyć w przepływie pracy async { ... } w języku F #.Jak Async.AwaitTask na zwykłym zadaniu (nie zadanie <T>)?

Widzę, że możemy Async.AwaitTask na async C# metody zwracając Task<T>, ale co z tymi zwracającymi zwykły Task?

Być może jest tam pomocnika do konwertowania ich do Async<unit> lub przekonwertować Task do Task<unit> więc będzie pracować z Async.AwaitTask?

Odpowiedz

43

Można użyć ContinueWith:

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

Or AwaitIAsyncResult z nieskończoną timeout:

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

Ach, widzę. Oczywiście, Zadanie jest przecież IAsyncResult. Skrócono do 'let awaitTask = Async.AwaitIAsyncResult >> Async.Ignore' Wielkie dzięki! – AshleyF

10

bardzo lubiłem sugestię Ashleya użyciu złożenie funkcji. Dodatkowo można przedłużyć moduł Async takiego:

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

Następnie pojawia się ona w IntelliSense wraz z Async.AwaitTask. Może być używany w następujący sposób:

do! Task.Delay delay |> Async.AwaitTaskVoid 

Jakieś sugestie dotyczące lepszej nazwy?

12

Aktualizacja:

Biblioteka FSharp.Core dla F # 4.0 zawiera teraz Async.AwaitTask przeciążenie, która akceptuje zwykły Task. Jeśli używasz F # 4.0, powinieneś użyć tej podstawowej funkcji zamiast poniższego kodu.


Oryginalny odpowiedź:

Jeśli zadanie mogłoby wyjątek to pewnie też chcą to sprawdzić. na przykład

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

'raise task.Exception' po prostu podniesie wyjątek AggregateException; prawdopodobnie lepiej jest uzyskać dostęp do kolekcji 'InnerExceptions' i podnieść pierwszą (o ile kolekcja nie jest pusta) –

1

Aby prawidłowo propagować zarówno wyjątki i anulowanie prawidłowo, myślę trzeba coś jak to (częściowo w oparciu o odpowiedzi usunięty 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)