SafeHandle和Dispose z
SafeHandle最大的意义是封装一个托管资源且本身会执行.NET中的资源释放模式(所谓的Dispose Pattern),这样,开发者在使用非托管资源时,不可以不需要执行繁琐的资源释放模式,而直接使用SafeHandle就可以了,另外SafeHandle继承自CriticalFinalizerObject类型,CLR对其的Finalize方法有特殊优化。
整个.NET Framework内有许多SafeHandle,比如.NET 4新加的SafeBuffer(在System.Runtime.InteropServices命名空间内),使用它可以申请非托管内存资源。这样的话就不需要直接使用Marshal.AllocHGlobal和FreeHGlobal方法了。
举一个简单的例子,使用GDI中的CreateSolidBrush返回一个非托管资源Handle,如果需要在类型中使用这个Handle,则要注意正确的资源释放,如下代码:
//+ using System.Runtime.InteropServices; //使用GDI中CreateSolidBrush中的资源 publicclassMyPen : IDisposable { bool _isDisposed; IntPtr _gdiBrush;
public MyPen() { _gdiBrush = CreateSolidBrush(0); }
publicvoid Dispose() { Dispose(true); //不需要析构函数再次运行了 GC.SuppressFinalize(this); }
//析构函数 ~MyPen() { Dispose(false); }
//protected Dispose,被公共Dispose和析构函数调用 protectedvirtualvoid Dispose(bool disposing) { if(_isDisposed) { return; } if (disposing) { //释放托管资源 } //释放非托管资源 if (_gdiBrush !=IntPtr.Zero) { DeleteObject(_gdiBrush); _gdiBrush =IntPtr.Zero; } _isDisposed =true; }
#region Win32 API [DllImport("gdi32.dll")] staticexternIntPtr CreateSolidBrush(uint crColor);
[DllImport("gdi32.dll", EntryPoint ="DeleteObject")] staticexternbool DeleteObject([In] IntPtr hObject);
#endregion }
而如果用SafeHandle类型定义的话,使用起非托管资源就方便多了。
首先,创建一个类型继承自Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid,改写ReleaseHandle方法来释放非托管资源。如下代码:
//+ using Microsoft.Win32.SafeHandles; //+ using System.Runtime.InteropServices; classSafeBrushHandle : SafeHandleZeroOrMinusOneIsInvalid { public SafeBrushHandle(IntPtr handle) : base(true) { base.SetHandle(handle); }
protectedoverridebool ReleaseHandle() { //判断Handle合法 if (!this.IsInvalid) { //释放资源 return DeleteObject(this.handle); } returntrue; }
[DllImport("gdi32.dll", EntryPoint ="DeleteObject")] staticexternbool DeleteObject([In] IntPtr hObject); }
然后使用这个SafeHandle,我们的MyPen类型的执行就简单多了:
//+ using System.Runtime.InteropServices; //使用SafeBrushHandle publicclassMyPen : IDisposable { bool _isDisposed; SafeBrushHandle _gdiBrush;
public MyPen() { _gdiBrush =newSafeBrushHandle(CreateSolidBrush(0)); }
publicvoid Dispose() { if (_isDisposed) { return; } _gdiBrush.Dispose(); _isDisposed =true; }
#region Win32 API [DllImport("gdi32.dll")] staticexternIntPtr CreateSolidBrush(uint crColor);
#endregion }
所以,使用SafeHandle可以让使用非托管资源类型的定义更加简洁,因为不需要再定义析构函数了。非托管资源被SafeHandle包装好后,整个资源对象会表现起来像一个托管的对象(注意是表现起来像,本质上显然不是),即便是忘了调用它的Dispose方法,非托管资源也会随着SafeHandle被垃圾回收时而释放,因为SafeHandle的析构函数(Finalize方法)会调用内部的ReleaseObject方法的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2013-05-04 Some Useful Extension Methods On IList<T> zt
2012-05-04 ICloneable