3

我正在使用一些使用平台调用的 F# 代码。我正在使用的 API 之一返回一个句柄。nativeint我没有使用 ,而是实现了自己的 SafeHandle(特别是SafeHandleMinusOneIsInvalid.)。这使得使用包含 pinvoke 签名的模块有点笨拙。这是一个例子:

type MySafeHandle() = 
    inherit SafeHandleZeroOrMinusOneIsInvalid(true)

    override this.ReleaseHandle() =
        NativeMethods.FreeHandle(base.handle)            
        true

module NativeMethods = 
    [<DllImport("mylibrary.dll")>]
    extern void GetHandle([<Out>]MySafeHandle& handle)
    [<DllImport("mylibrary.dll")>]
    extern void FreeHandle(nativeint handle)

这不会编译,因为模块和类递归地相互引用,这是行不通的。如果我将模块移到上面MySafeHandle,则GetHandle看不到 SafeHandle。

我无法将平台调用方法移到内部,MySafeHandle因为 F# 中的外部方法似乎必须在模块中(即使编译器不会阻止您尝试将它们放入类中)。

似乎 F# 的递归类型在模块和类之间不起作用,只是在类之间起作用。

这个问题有没有不需要声明两个不同模块的解决方案?理想情况下,我希望将我的所有平台调用代码组织到一个模块中。

4

1 回答 1

1

好吧,我知道一个,因为我自己也有同样的问题。

问题是,我猜它有点丑:

它涉及您稍后在模块中设置为导入函数的静态引用。

type MySafeHandle() = 
    inherit SafeHandleZeroOrMinusOneIsInvalid(true)
    static let freeHandle = ref Unchecked.defaultof<_>
    static member internal SetFreeHandleRef value = freeHandle := value

    override this.ReleaseHandle() =
        !freeHandle base.handle            
        true

module NativeMethods = 
    [<DllImport("mylibrary.dll")>]
    extern void GetHandle([<Out>]MySafeHandle& handle)
    [<DllImport("mylibrary.dll")>]
    extern void FreeHandle(nativeint handle)

    MySafeHandle.SetFreeHandleRef FreeHandle
于 2014-07-28T21:18:00.553 回答