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的更多相关文章

  1. [JAVA] 一个可以编辑、编译、运行Java简单文件的记事本java实现

    本来是Java课做一个仿windows记事本的实验,后来突然脑子一热,结果就给它加了一个编译运行Java文件的功能. 本工程总共大约3000行代码,基本上把所学的java界面.文件.控件的功能都包含在 ...

  2. 【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 ...

  3. Finalize()、Dispose()、SafeHandle、GC

    Finalize https://msdn.microsoft.com/en-us/library/system.object.finalize%28v=vs.110%29.aspx https:// ...

  4. safehandle 和析构函数

    safehandle 是一种析构机制,她和析构函数有什么分别. 首先要理解析构函数.析构函数在.net中是没有顺序的,因此你不能假定另一个对象的析构函数在你之后运行,哪怕它是你的成员!如果你的成员也有 ...

  5. 第七节:使用实现了dispose模式的类型

    知道类型如何实现dispose模式之后,接下来看一下开发人员怎样使用提供了dispose模式的类型.这里不再讨论前面的SafeHandle类,而是讨论更常用的FileStream类. 可以利用File ...

  6. DevExpress控件汉化类 z

    更新了一些字段,VER9.3.3 using System; using DevExpress.XtraEditors.Controls; using DevExpress.XtraGrid.Loca ...

  7. C# 调整控件的Z顺序

    当窗口或者容器控件中的控件在布局过程中发生重叠的时候,会出现层次性.Z顺序较大的控件会遮挡Z顺序较小的控件,放在顶层的控件会挡住放在底层的控件. 1.编辑一个这样的窗口(使用Label控件) 2.添加 ...

  8. Implementing a Dispose method

    [Implementing a Dispose method] 1.实现System.IDsiposable.Dispose()方法.不能将此方法设置为virtual,子类不能override此方法. ...

  9. C#之Dispose

    前言 谈到Dispose,首先需要理解C#的资源 资源类型 托管资源:由CLR创建和释放 非托管资源:资源的创建和释放不由CLR管理.比如IO.网络连接.数据库连接等等.需要开发人员手动释放. 如何释 ...

随机推荐

  1. 【学习总结】整理一下int, NSInteger 等概念

    基本需要知道的 : unsigned : 没符号的 signed  : 有符号的 int : 整型 看看OC的定义 : #if __LP64__ || (TARGET_OS_EMBEDDED & ...

  2. 0ffice365 Calendar API

    Calendar REST API in Office 365 APIs Preview http://msdn.microsoft.com/EN-US/library/office/dn792114 ...

  3. python学习笔记6(字典)

    映射:键值对的关系,键(key)映射值(value) 字典是Python唯一的映射类型 >>> phonebook = {'} >>> phonebook {'} ...

  4. 微软Hololens设备 浅分析

    微软Hololens的定位是一款MR 设备(Mixed reality).MR与AR的不同我认为是MR能够将真实环境的场景信息与虚拟对象进行完美的融合,它是基于SLAM(SimultaneousLoc ...

  5. QR code 金庸小说体(二)

    传说 在二维码世纪,流传着这样一个传说,long long ago,武林一片混乱,这时魔教二长老创立了一门绝世武功——QR code,随后称霸武林.但同时也遭到武林中人的觊觎和反抗,各大武林正派掌门人 ...

  6. Sublime Text 3 安装及简单配置

    Sublime Text 3, 一款不错的文本编辑器, 加上各种插件和IDE就能化身各种语言的编译器, 界面以及多种插件的灵活组合搭配更是让程序员们在码代码这种枯燥的生活中增加一点调剂. 下载地址 点 ...

  7. Workspace in use or cannot be created, choose a different one.--错误解决办法

    eclipse 使用一段时间后,有时会因为一些故障自己就莫名奇妙的关闭了,再打开时有时没有问题,有时有会提示错误 Workspace Unavailable: 原因:出现这种情况一般是workspac ...

  8. jQuery 如何先创建、再修改、后添加DOM元素

    例如顺序执行[创建]-> [修改]-> [添加]三个动作. 由于jQuery支持链式操作,其实就是设计模式的builder模式,所以我们可以把三个操作串在一起来执行. 首先创建一个p元素, ...

  9. ASP + ACCESS 上传图片到数据库与将图片读出数据库显示之实现

    1.uppic.asp:上传图片程序 <% dim rs dim formsize,formdata,bncrlf,divider,datastart,dataend,mydata formsi ...

  10. ***CI异常记录到日志:CodeIgniter中设计一个全局exception hook

    在CodeIgniter中,当发生异常时,经常要通知系统管理员,因此有必要在全局的高度上 捕捉异常,因此可以写一个hook, 比如在config目录的hook.php中,加入: $hook['pre_ ...