在F#中使用SafeHandles

时间:2014-07-28 21:02:56

标签: f# safehandle

我正在使用一些使用平台调用的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#must be in modules中的外部方法(即使编译器不会阻止你尝试放置他们在课堂上。)

似乎F#的recursive types不在模块和类之间工作,只是在类之间。

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

1 个答案:

答案 0 :(得分: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