在F#async
工作流程中,我们可以定义应使用use
关键字清理的资源。
但是use
与return
如何相互作用?
例如,给出以下代码:
let createResource = async {
use r = Resource ()
do! operationThatMightThrow r
return r
}
async {
use! r = createResource
printfn "%O" r
}
|> Async.RunSynchronously
对Resource.Dispose
的呼叫会在哪里发生?
我该如何设计以便始终清理r
(即使抛出operationThatMightThrow
)?
答案 0 :(得分:2)
它们将在从计算表达式返回值之前发生,从语义上讲,它们将在finally
块中发生。如果要查看生成的using语句的来源,可以找到它here。它有效地生成了一个访问控制的处置函数,该函数在您传入的资源上调用Dispose()
,然后在finally子句中使用该函数进行异步try-finally块。
答案 1 :(得分:0)
我通常有两种解决方法。
第一个解决方案是主动捕获异常,手动处理一次性对象,然后重新抛出异常:
let createResource = async {
let r = new Resource ()
try do! operationThatMightThrow r
with e -> (r :> IDisposable).Dispose(); raise e
return r
}
第二种解决方案是使用一个连续函数,该函数将在异步返回之前访问一次性对象:
let createResource cont = async {
use r = new Resource ()
do! operationThatMightThrow r
return cont r
}
async {
let! x = createResource (fun r -> printfn "in cont: %O" r)
...
}