以类型安全的方式制定IntPtr

hul*_*ist 3 c# pinvoke marshalling

我有以下c函数

opaque_struct* create() {}
void free(opaque_struct*) {}
Run Code Online (Sandbox Code Playgroud)

我想用PInvoke调用它:

[DllImport("test")]
public static extern IntPtr create ();
[DllImport("test")]
public static extern void free (IntPtr);
Run Code Online (Sandbox Code Playgroud)

我想这样可以正常工作,但我正在寻找一种方法,在托管代码中明确声明"free"只接受由"create"返回的IntPtr,并避免意外传递从其他函数接收的其他IntPtr.

就所有托管代码而言,指向的结构是不透明的.

即使我只是给它一个新名称,没有额外的属性,也无法扩展IntPtr.

有没有办法制作这种类型的IntPtr?

ken*_*n2k 6

在处理非托管内存时,每个定义总是存在"意外"的可能性.

这就是说,你可以做的是换你IntPtr的一类,就像微软用自己做的SafeHandle类及相关SafeFileHandle,SafePipeHandle...等等.

您可以创建自己的SafeHandle类(可以继承System.Runtime.InteropServices.SafeHandle),并在P/Invoke声明中使用它:

[DllImport("test")]
public static extern MySafeHandle create ();

[DllImport("test")]
public static extern void free (MySafeHandle pointer);
Run Code Online (Sandbox Code Playgroud)

另一个好处SafeHandle是它实现IDisposable并因此允许使用该using语句来确保始终调用您的free()方法:

using (MySafeHandle ptr = create())
{
    // Use your ptr instance here
    // You can retrieve the IntPtr value itself using
    // ptr.DangerousGetHandle()

    // When you get out of the scope of the using(), the MySafeHandle
    // object will be disposed and ptr.ReleaseHandle() will be called.
    // Just add your call to free() in the overriden ReleaseHandle method
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,甚至不需要free()手动调用,因为它在SafeHandle处理时自动完成.