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(); }
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()); }
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方法的。
SafeHandle和Dispose z的更多相关文章
- [JAVA] 一个可以编辑、编译、运行Java简单文件的记事本java实现
本来是Java课做一个仿windows记事本的实验,后来突然脑子一热,结果就给它加了一个编译运行Java文件的功能. 本工程总共大约3000行代码,基本上把所学的java界面.文件.控件的功能都包含在 ...
- 【Python】使用torrentParser1.03对多文件torrent的分析结果
Your environment has been set up for using Node.js 8.5.0 (x64) and npm. C:\Users\horn1>cd C:\User ...
- Finalize()、Dispose()、SafeHandle、GC
Finalize https://msdn.microsoft.com/en-us/library/system.object.finalize%28v=vs.110%29.aspx https:// ...
- safehandle 和析构函数
safehandle 是一种析构机制,她和析构函数有什么分别. 首先要理解析构函数.析构函数在.net中是没有顺序的,因此你不能假定另一个对象的析构函数在你之后运行,哪怕它是你的成员!如果你的成员也有 ...
- 第七节:使用实现了dispose模式的类型
知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型.这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类. 可以利用File ...
- DevExpress控件汉化类 z
更新了一些字段,VER9.3.3 using System; using DevExpress.XtraEditors.Controls; using DevExpress.XtraGrid.Loca ...
- C# 调整控件的Z顺序
当窗口或者容器控件中的控件在布局过程中发生重叠的时候,会出现层次性.Z顺序较大的控件会遮挡Z顺序较小的控件,放在顶层的控件会挡住放在底层的控件. 1.编辑一个这样的窗口(使用Label控件) 2.添加 ...
- Implementing a Dispose method
[Implementing a Dispose method] 1.实现System.IDsiposable.Dispose()方法.不能将此方法设置为virtual,子类不能override此方法. ...
- C#之Dispose
前言 谈到Dispose,首先需要理解C#的资源 资源类型 托管资源:由CLR创建和释放 非托管资源:资源的创建和释放不由CLR管理.比如IO.网络连接.数据库连接等等.需要开发人员手动释放. 如何释 ...
随机推荐
- MVC使用的MetaModel代码生成器模板
代码生成器能使从一些重复的工作中缓解下来 在最近开发MVC项目中使用到了MetaModel用来设定Model的显示名称,数据限制的代码生成模板,自己第一做代码生成模板还有很多缺陷. 下面是模板代码: ...
- 微软职位内部推荐-Sr DEV Lead, Bing Search Relevance
微软近期Open的职位: Contact Person: Winnie Wei (wiwe@microsoft.com )Sr DEV Lead, Bing Search RelevanceLocat ...
- iOS10 权限崩溃问题-b
手机升级了 iOS10 Beta,然后用正在开发的项目 装了个ipa包,发现点击有关 权限访问 直接Crash了,并在控制台输出了一些信息: This app has crashed because ...
- TWaver初学实战——如何在TWaver属性表中添加日历控件?
在日期输入框中添加日历控件,是一种非常流行和实用的做法.临渊羡鱼不如退而写代码,今天就看看在TWaver中是如何实现的. 资源准备 TWaver的在线使用文档中,就有TWaver Proper ...
- 企业应用的Web程序的安全性
提起安全性这个话题,大家恐怕依稀还记得Sony的PSP账户信息泄露的事故造成的重大损失.但是又隐隐觉得这事儿离我很远,无需过多考虑.也有的人会想,我们做的是企业内部系统所以不必太在意.但是,Web程序 ...
- ArcGIS Engine实现LAS数据集转RASTER
ArcGIS 10.1版本开始提供了将LAS数据集转换为栅格的新功能,最近在做LAS数据处理时通过ArcGIS Engine10.1+C#实现了LAS数据集转RASTER,既然ArcGIS DeskT ...
- 在js中获取easyui datagrid的数据
可以在页面对datagrid的数据直接进行修改,然后提交到数据库,但是要求在提交前获取datagrid的所有行的数据.API提供了getData方法,但是怎么用了,没说. 最后这样写才搞定 var a ...
- PAT-乙级-1015. 德才论 (25)
1015. 德才论 (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Li 宋代史学家司马光在<资治通鉴&g ...
- HeadFirst设计模式之组合模式
一. 1.The Composite Pattern allows us to build structures of objects in the form of trees that contai ...
- “WIZnet杯”以太网技术竞赛即将开始!