5

在 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抛出)?

4

2 回答 2

2

它们将在从计算表达式返回值之前发生,从语义上讲,它们将发生在一个finally块中。如果您想查看生成的 using 语句的来源,可以在此处找到。它有效地生成一个访问控制的 dispose 函数,该函数调用Dispose()您传入的资源,然后在 finally 子句中使用该函数创建一个异步 try-finally 块。

于 2019-05-24T19:16:37.850 回答
2

我通常有两种解决方案。

第一种方案是主动捕获异常,手动dispos一次性对象,重新抛出异常:

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)
    ...
}
于 2019-05-25T04:50:57.577 回答