3

我正在使用一个externDLL,它有一堆返回ReturnCode枚举的例程,所以我编写了以下帮助函数来记录所有错误:

let mutable LastError = ReturnCode.OK
let mutable LastReturnCode = ReturnCode.OK
let mutable TotalErrors = 0

let Run (call: unit -> ReturnCode) =
  LastReturnCode <- call()
  if LastReturnCode <> ReturnCode.OK then
    LastError <- LastReturnCode
    TotalErrors <- TotalErrors + 1

很好,除了一些 DLL 的函数有out参数。所以现在当我做类似的事情时

let CreateEvfImageRef (streamHandle: int) =
  let mutable evfImageHandle = 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &evfImageHandle))
  evfImageHandle

编译器给了我一个“可变变量不能被闭包捕获”错误。Run除了到处内联之外,我还能做些什么吗?这在 C# 中运行良好。

(下面的外部声明示例)

[<DllImport(EDSDKPath)>]
extern ReturnCode EdsCreateEvfImageRef(int inStreamHandle, [<Out>] int& outEvfImageHandle);
4

2 回答 2

6

您应该仍然可以使用该类型,但在将引用传递给函数时ref不需要编写符号 - 编译器会自动执行此操作:&

let CreateEvfImageRef (streamHandle: int) =
  let mutable evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, evfImageHandle))
  !evfImageHandle
于 2013-06-24T09:13:05.267 回答
3

标准解决方案是使用引用 - 代码变为

let CreateEvfImageRef (streamHandle: int) =
  let evfImageHandle = ref 0
  Run (fun () -> Extern.EdsCreateEvfImageRef (streamHandle, &(!evfImageHandle)))
  !evfImageHandle

但是,这不起作用,因为编译器需要!evfImageHandle是可变的,但事实并非如此。

我认为这里真正的解决方案是更改您的Run函数,使其不采用闭包,而是让它只采用返回值 - 这至少在这种情况下可以工作。然后代码变成

let Run (call: ReturnCode) =
  LastReturnCode <- call
  if LastReturnCode <> ReturnCode.OK then
    LastError <- LastReturnCode
    TotalErrors <- TotalErrors + 1

并且代码更改为

let CreateEvfImageRef (streamHandle: int) =
  let mutable evfImageHandle = 0
  Extern.EdsCreateEvfImageRef (streamHandle, &evfImageHandle)) |> Run
  evfImageHandle

或者更骇人听闻的解决方案。利用数组成员是可变的并且可以被闭包捕获的事实来做

let CreateEvfImageRef (streamHandle: int) =
  let evfImageHandle =  [|0|]
  Run (fun () -> EdsCreateEvfImageRef (streamHandle, &(evfImageHandle.[0])) )
  evfImageHandle.[0]
于 2013-06-24T02:35:02.693 回答