IDisposable 如何与 use 和 return 一起使用?
How does IDisposable work with use and return?
在 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
抛出)?
它们将在计算表达式返回值之前发生,从语义上讲,它们将发生在 finally
块中。如果想查看生成的using语句的来源,可以找here。它有效地生成一个 access-controlled dispose 函数,该函数在您传入的资源上调用 Dispose()
,然后在 finally 子句中使用该函数创建一个异步 try-finally 块。
我通常有两种解决方案。
第一种方案是主动捕获异常,手动处理一次性对象,re-throwing异常:
let createResource = async {
let r = new Resource ()
try do! operationThatMightThrow r
with e -> (r :> IDisposable).Dispose(); raise e
return r
}
第二种解决方案是使用延续函数,该函数将在异步之前访问一次性对象 returns:
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)
...
}
在 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
抛出)?
它们将在计算表达式返回值之前发生,从语义上讲,它们将发生在 finally
块中。如果想查看生成的using语句的来源,可以找here。它有效地生成一个 access-controlled dispose 函数,该函数在您传入的资源上调用 Dispose()
,然后在 finally 子句中使用该函数创建一个异步 try-finally 块。
我通常有两种解决方案。
第一种方案是主动捕获异常,手动处理一次性对象,re-throwing异常:
let createResource = async {
let r = new Resource ()
try do! operationThatMightThrow r
with e -> (r :> IDisposable).Dispose(); raise e
return r
}
第二种解决方案是使用延续函数,该函数将在异步之前访问一次性对象 returns:
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)
...
}