web-dev-qa-db-ja.com

プレーンタスク(Task <T>ではない)でAsync.AwaitTaskを実行する方法は?

F#でC#ライブラリを使用しようとしています。ライブラリはasync/awaitを多用します。 F#のasync { ... }ワークフロー内で使用したい。

Async.AwaitTaskを返す非同期C#メソッドでTask<T>できるようですが、プレーンなTaskを返すメソッドはどうでしょうか。

おそらく、これらをAsync<unit>に変換したり、TaskTask<unit>に変換して、Async.AwaitTaskで動作するようにするヘルパーはありますか?

35
AshleyF

あなたはContinueWithを使うことができます:

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

または、無限タイムアウトのAwaitIAsyncResult:

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

更新:

F#4.0のFSharp.Coreライブラリには、プレーンなTaskを受け入れるAsync.AwaitTaskオーバーロードが含まれるようになりました。 F#4.0を使用している場合は、以下のコードの代わりにこのコア関数を使用する必要があります。


元の回答:

タスクが例外をスローする可能性がある場合は、おそらくこれも確認する必要があります。例えば.

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

更新:

F#4.0のFSharp.Coreライブラリに、プレーンタスクを受け入れるAsync.AwaitTaskオーバーロードが含まれるようになりました。 F#4.0を使用している場合は、以下のコードの代わりにこのコア関数を使用する必要があります。

元の回答:

関数合成を使ったアシュリーの提案が本当に気に入りました。さらに、次のように非同期モジュールを拡張できます。

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

次に、Async.AwaitTaskとともにIntellisenseに表示されます。これは次のように使用できます。

do! Task.Delay delay |> Async.AwaitTaskVoid

より良い名前の提案はありますか?

11
Wallace Kelly

例外とキャンセルの両方を適切に伝播するには、I think次のようなものが必要です(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)
1
svick