我正在尝试在 F# 中使用 C# 库。该库大量使用 async/await。我想async { ... }
在 F# 的工作流中使用。
我看到我们可以Async.AwaitTask
在异步 C# 方法上返回Task<T>
,但是那些返回普通的Task
呢?
也许,是否有帮助将这些转换为Async<unit>
或转换Task
为Task<unit>
以便它可以使用Async.AwaitTask
?
我正在尝试在 F# 中使用 C# 库。该库大量使用 async/await。我想async { ... }
在 F# 的工作流中使用。
我看到我们可以Async.AwaitTask
在异步 C# 方法上返回Task<T>
,但是那些返回普通的Task
呢?
也许,是否有帮助将这些转换为Async<unit>
或转换Task
为Task<unit>
以便它可以使用Async.AwaitTask
?
您可以使用 ContinueWith:
let awaitTask (t: Task) = t.ContinueWith (fun t -> ()) |> Async.AwaitTask
或无限超时的 AwaitIAsyncResult:
let awaitTask (t: Task) = t |> Async.AwaitIAsyncResult |> Async.Ignore
更新:
F# 4.0 的 FSharp.Core 库现在包括一个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 ()
}
更新:
F# 4.0 的 FSharp.Core 库现在包括一个接受普通任务的 Async.AwaitTask 重载。如果您使用的是 F# 4.0,那么您应该使用这个核心函数而不是下面的代码。
原答案:
我真的很喜欢 Ashley 使用函数组合的建议。此外,您可以像这样扩展 Async 模块:
module Async =
let AwaitTaskVoid : (Task -> Async<unit>) =
Async.AwaitIAsyncResult >> Async.Ignore
然后它与 Async.AwaitTask 一起出现在 Intellisense 中。它可以这样使用:
do! Task.Delay delay |> Async.AwaitTaskVoid
有更好的名字的建议吗?
为了正确传播异常和取消,我认为您需要这样的东西(部分基于 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)