IDisposable如何与使用和退货一起使用?

时间:2019-05-24 19:04:42

标签: asynchronous f# disposable

在F#async工作流程中,我们可以定义应使用use关键字清理的资源。

但是usereturn如何相互作用?

例如,给出以下代码:

let createResource = async {
  use r = Resource ()

  do! operationThatMightThrow r

  return r
}

async {
  use! r = createResource

  printfn "%O" r
}
|> Async.RunSynchronously

Resource.Dispose的呼叫会在哪里发生?

我该如何设计以便始终清理r(即使抛出operationThatMightThrow)?

2 个答案:

答案 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)
    ...
}