Как Async.AwaitTask в простой задаче (не Task <T>)?

Я пытаюсь использовать библиотеку С# в F #. В библиотеке широко используется async/wait. Я хочу использовать в рабочем процессе async { ... } в F #.

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

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

Ответы

Ответ 1

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

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

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

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

Ответ 2

Update:

Библиотека 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 ()
    }

Ответ 3

Обновление:

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

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

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

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

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

do! Task.Delay delay |> Async.AwaitTaskVoid

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

Ответ 4

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

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)