SafeHandle 和 Dispose
SafeHandle 和 Dispose
这是从 https://www.cnblogs.com/zeroone/p/3708112.html 复制过来的,原文的格式不够好,重新排版一下。
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 中的资源
public class MyPen : IDisposable
{
bool _isDisposed;
IntPtr _gdiBrush;
public MyPen()
{
_gdiBrush = CreateSolidBrush(0);
}
publicvoid Dispose()
{
Dispose(true);
// 不需要析构函数再次运行了
GC.SuppressFinalize(this);
}
//析构函数
~MyPen()
{
Dispose(false);
}
//protected Dispose,被公共Dispose和析构函数调用
protected virtual void 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")]
static extern IntPtr 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;
class SafeBrushHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeBrushHandle(IntPtr handle): base(true)
{
base.SetHandle(handle);
}
protected override bool ReleaseHandle()
{
//判断 Handle 合法
if (!this.IsInvalid)
{
//释放资源
return DeleteObject(this.handle);
}
return true;
}
[DllImport("gdi32.dll", EntryPoint ="DeleteObject")]
static extern bool DeleteObject([In] IntPtr hObject);
}
然后使用这个 SafeHandle,我们的 MyPen 类型的执行就简单多了:
using System.Runtime.InteropServices;
// 使用 SafeBrushHandle
public class MyPen : IDisposable
{
bool _isDisposed;
SafeBrushHandle _gdiBrush;
public MyPen()
{
_gdiBrush = new SafeBrushHandle( CreateSolidBrush(0) );
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
_gdiBrush.Dispose();
_isDisposed =true;
}
#region Win32 API
[DllImport("gdi32.dll")]
static extern IntPtr CreateSolidBrush(uint crColor);
#endregion
}
所以,使用 SafeHandle 可以让使用非托管资源类型的定义更加简洁,因为不需要再定义析构函数了。非托管资源被 SafeHandle 包装好后,整个资源对象会表现起来像一个托管的对象(注意是表现起来像,本质上显然不是),即便是忘了调用它的Dispose 方法,非托管资源也会随着 SafeHandle 被垃圾回收时而释放,因为 SafeHandle 的析构函数(Finalize方法)会调用内部的 ReleaseObject 方法的。
参考资料
SafeHandle 和 Dispose的更多相关文章
- SafeHandle和Dispose z
SafeHandle最大的意义是封装一个托管资源且本身会执行.NET中的资源释放模式(所谓的Dispose Pattern),这样,开发者在使用非托管资源时,不可以不需要执行繁琐的资源释放模式,而直接 ...
- 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 ...
- Implementing a Dispose method
[Implementing a Dispose method] 1.实现System.IDsiposable.Dispose()方法.不能将此方法设置为virtual,子类不能override此方法. ...
- C#之Dispose
前言 谈到Dispose,首先需要理解C#的资源 资源类型 托管资源:由CLR创建和释放 非托管资源:资源的创建和释放不由CLR管理.比如IO.网络连接.数据库连接等等.需要开发人员手动释放. 如何释 ...
- 【C# .Net GC】清除非托管类型(Finalize终结器、dispose模式以及safeHandler)
总结 1.一般要获取一个内核对象的引用,最好用SafeHandle来引用它,这个类可以帮你管理引用计数,而且用它引用内核对象,代码更健壮 2.托管中生成并引用非托管,一但非托管和托管中的引用断开(托管 ...
- Delphi的分配及释放---New/Dispose, GetMem/FreeMem及其它函数的区别与相同
转载自:http://www.cnblogs.com/qiusl/p/4028437.html?utm_source=tuicool 我估摸着内存分配+释放是个基础的函数,有些人可能没注意此类函数或细 ...
- JS魔法堂:定义页面的Dispose方法——[before]unload事件启示录
前言 最近实施的同事报障,说用户审批流程后直接关闭浏览器,操作十余次后系统就报用户会话数超过上限,咨询4A同事后得知登陆后需要显式调用登出API才能清理4A端,否则必然会超出会话上限. 即使在页面 ...
- C#学习笔记---Dispose(),Finalize(),SuppressFinalize
http://www.cnblogs.com/eddyshn/archive/2009/08/19/1549961.html 在.NET的对象中实际上有两个用于释放资源的函数:Dispose和Fina ...
随机推荐
- KASAN 中kasan_multi_shot 的作用
kasan_multi_shot 是 Linux 内核配置选项之一,与 Kernel Address Sanitizer (KASAN) 相关.KASAN 是一种内核内存错误检测工具,能够检测内核代码 ...
- USB协议详解第4讲(USB描述符-标准配置描述符)
1.USB描述符 USB描述符有设备描述符.标准配置描述符.接口描述符.端点描述符.字符串描述符,HID设备有HID描述符.报告描述符和物理描述符.今天主要是学习USB标准配置描述符的组成. 2.标准 ...
- FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
<FFmpeg开发实战:从零基础到短视频上线>一书的"5.1.2 把音频流保存为PCM文件"介绍了如何把媒体文件中的音频流转存为原始的PCM音频,在样例代码的转存过 ...
- Machine Learning Week_1 Linear Algebra Review 1-6
目录 4 Linear Algebra Review 4.1 Video: Matrices and Vectors unfamiliar words 4.2 Reading: Matrices an ...
- MongoDB聚合类操作
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果.有点类似sql语句中的 count(*) 语法:db.tablename.aggregat ...
- OpenFeign简单使用
OpenFeign入门 什么是 OpenFeign? OpenFeign是一个远程访问的组件,用于两个微服务之间互相访问的中间件 OpenFeign使用步骤 1.添加OpenFeign的依赖 < ...
- .NET 全能高效的 CMS 内容管理系统
前言 推荐一款强大的企业级工具 - SSCMS 内容管理系统. SSCMS 为企业级客户设计,完全开源免费,适用于商业用途且无需支付任何产品或授权费用. 本文将详细介绍 SSCMS 系统的功能.用户界 ...
- 遗传算法+强化学习—TPG—Emergent Tangled Graph Representations for Atari Game Playing Agents_2
最近在看进化算法在强化学习(RL)领域的一些应用,有些论文中将使用进化算法解决强化学习问题的算法归为非强化学习算法,然而又有些论文把使用进化算法解决强化学习问题的算法归为强化学习算法,不过更多的论文是 ...
- 记录一下opencv-contrib的编译使用
一.来由 公司需求进行多图拼接算法,在opencv提供的Stitcher类当中默认的算子是ORB,我想尝试使用SIFT和SURF算子,经过一番查找发现这两个算子需要opencv的超集库支持--&quo ...
- 推荐7款程序员常用的API管理工具
前言 现如今API接口的编写与调试已成为开发人员不可或缺的技能,工欲善其事,必先利其器,选择一款优秀的API管理工具显得尤为重要.本文大姚给大家推荐7款程序员常用的API管理工具,大家可以根据自身和团 ...