在 F# 中使用 SafeHandles

Posted

技术标签:

【中文标题】在 F# 中使用 SafeHandles【英文标题】:Working with SafeHandles in F# 【发布时间】:2014-07-28 21:02:56 【问题描述】:

我正在处理一些使用平台调用的 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 中的 extern 方法似乎存在(即使编译器不会阻止您尝试将它们放入类中)。

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

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

【问题讨论】:

两个模块确实是最干净的解决方案。 【参考方案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

【讨论】:

以上是关于在 F# 中使用 SafeHandles的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中定义 F# '**' 运算符

在 F# 中使用机器学习的资源 [关闭]

在多个表中使用count(decode ...)

在 Python 中使用 %f 和 strftime() 来获得微秒

F# 在同一项目的另一个文件中定义/使用类型/模块

在 Rails 中使用“f.input 集合”的 onChange 方法