我最近才了解到SafeHandle
,为了测试,我为 SDL2 库实现了它,创建和销毁一个窗口:
[DllImport(_libName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr SDL_CreateWindow(
[MarshalAs(UnmanagedType.LPStr)] string title, int x, int y, int w, int h, uint flags);
[DllImport(_libName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void SDL_DestroyWindow(IntPtr window);
public class Window : SafeHandleZeroOrMinusOneIsInvalid
{
public Window() : base(true)
{
SetHandle(SDL_CreateWindow("Hello", 400, 400, 800, 600, 0));
}
protected override bool ReleaseHandle()
{
SDL_DestroyWindow(handle);
return true;
}
}
这很好用,然后我了解到使用的另一个优点SafeHandle
:可以直接使用 p/invoke 签名中的类,如下所示:
[DllImport(_libName, CallingConvention = CallingConvention.Cdecl)]
internal static extern Window SDL_CreateWindow(
[MarshalAs(UnmanagedType.LPStr)] string title, int x, int y, int w, int h, uint flags);
[DllImport(_libName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void SDL_DestroyWindow(Window window);
这当然比泛型IntPtr
参数/返回要好得多,因为我有类型安全Window
向/从这些方法传递/检索实际(句柄)。
虽然这适用于SDL_CreateWindow
,它现在正确返回一个Window
实例,但它不适用于SDL_DestroyWindow
,它由我在内部调用,Window.ReleaseHandle
如下所示:
public Window() : base(true)
{
SetHandle(SDL_CreateWindow("Hello", 400, 400, 800, 600, 0).handle);
}
protected override bool ReleaseHandle()
{
SDL_DestroyWindow(this);
return true;
}
当试图传递this
给时SDL_DestroyWindow
,我得到一个ObjectDisposedException
:安全句柄已关闭。确实,该IsClosed
物业是true
,我没想到此时会出现。显然它在内部尝试增加引用计数,但注意IsClosed
是true
. 根据文档,它已设置为true
因为“调用了 Dispose 方法或 Close 方法,并且在其他线程上没有对 SafeHandle 对象的引用。”,所以我猜Dispose
之前在调用堆栈中隐式调用了我的ReleaseHandle
.
ReleaseHandle
如果我想在 p/invoke 签名中使用类参数,显然不是清理的正确位置,所以我想知道是否有任何方法可以在不破坏SafeHandle
内部结构的情况下进行清理?