Как выполнить Async.AwaitTask для простой задачи (не задача <T>)? - PullRequest
33 голосов
/ 06 ноября 2011

Я пытаюсь использовать библиотеку C # в F #. Библиотека активно использует async / await. Я хочу использовать в async { ... } рабочий процесс в F #.

Я вижу, что мы можем Async.AwaitTask при асинхронных методах C #, возвращающих Task<T>, но как насчет тех, которые возвращают обычный Task?

Возможно, есть помощник для преобразования их в Async<unit> или для преобразования Task в Task<unit>, чтобы он работал с Async.AwaitTask?

Ответы [ 4 ]

44 голосов
/ 06 ноября 2011

Вы можете использовать ContinueWith:

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

Или AwaitIAsyncResult с бесконечным таймаутом:

let awaitTask (t: Task) = t |> Async.AwaitIAsyncResult |> Async.Ignore
14 голосов
/ 27 ноября 2014

Обновление:

Библиотека FSharp.Core для F # 4.0 теперь включает перегрузку Async.AwaitTask, которая принимает простое значение Task. Если вы используете F # 4.0, вам следует использовать эту базовую функцию вместо приведенного ниже кода.


Оригинальный ответ:

Если ваша задача может вызвать исключение, вы, вероятно, также захотите проверить это. например,

let awaitTask (task : Task) =
    async {
        do! task |> Async.AwaitIAsyncResult |> Async.Ignore
        if task.IsFaulted then raise task.Exception
        return ()
    }
10 голосов
/ 03 мая 2014

Мне очень понравилось предложение Эшли, использующее композицию функций.Кроме того, вы можете расширить модуль Async следующим образом:

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

Затем он появляется в Intellisense вместе с Async.AwaitTask.Его можно использовать так:

do! Task.Delay delay |> Async.AwaitTaskVoid

Есть предложения по улучшению имени?

1 голос
/ 12 июня 2015

Чтобы правильно распространять исключения и отмену, я думаю вам нужно что-то вроде этого (частично на основе удаленного ответа Томаша Петржичека):

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