Работа с SafeHandles в F#
Я работаю с некоторым кодом 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
поскольку кажется, что методы extern в F# должны быть в модулях (даже если компилятор не остановит вас от попыток поместить их в класс).
Также кажется, что рекурсивные типы F# не работают между модулем и классом, только классы.
Есть ли решение этой проблемы, которое не требует объявления двух разных модулей? В идеале я хотел бы, чтобы весь код вызова моей платформы был организован в одном модуле.
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