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 ...
随机推荐
- 利用 Page Visibility API 优化网页性能与用户体验
在现代 Web 开发中,用户可能会频繁切换标签页,或让网页处于后台运行.为了避免不必要的资源浪费并提升用户体验,合理利用 Page Visibility API 可以在页面不可见时暂停或减少资源的消耗 ...
- 《Vue.js 设计与实现》读书笔记 - 第13章、异步组件与函数式组件
第13章.异步组件与函数式组件 13.1 异步组件要解决的问题 用户可以简单通过 import 异步导入组件. <template> <component :is="asy ...
- vue 赶鸭子上架入门笔记(一) 安装开发环境
准备接手一个 vue 的前端项目,从零开始学习 vue.目标不高大上,能看得懂代码,能进行简单的修改,改完能打包和部署. 首先解决 vue 开发环境的准备.访问 Node.js 官方网站,下载适合你操 ...
- 通过一个题目三种变式讲清楚go接口类型断言
[第一种]一种类型实现多个接口,各个接口变量调用各自的方法 type Work struct { i int } func (w Work) ShowA() int { return w.i + 10 ...
- NICE与静态优先级的关系
在Linux系统中,nice值和静态优先级用于控制进程调度的优先级,但它们的范围和含义有所不同.让我们详细解释一下两者的区别和联系. 1. Nice值 范围:nice值的范围是从 -20 到 19. ...
- 同步完善Docker常用操作命令
镜像 images_name 表示镜像名 con_name表示容器名 #获取镜像 docker pull images_name #查看已有的docker镜像 docker images #删除镜像 ...
- 关于sizeof、strlen的理解与辨析以及strlen的模拟实现
关于sizeof.strlen的理解与辨析以及strlen的模拟实现 1. sizeof() sizeof的作用: 计算变量所占内存内存空间大小,单位是字节. 注意事项: ① 首先要明确的一点是:si ...
- CMake 生成器表达式---条件表达式和逻辑运算符
[写在前面] CMake 的生成器表达式用于在构建系统级别上进行条件判断和逻辑运算,它们通常用在目标属性和生成器表达式上下文中.这些表达式允许你根据不同的平台.配置或编译器来定制构建过程. 本文引用的 ...
- Rust 版本一直是 1.4 或者其它版本
Rust 版本一直是 1.4 或者其它版本 通过rustup update 升级或者 rustup default 设置版本也不行 解决方法 删除 rust-toolchain 这个东西,这个东西覆盖 ...
- 3.19 Linux命令的执行过程是怎样的?(新手必读)
前面讲过,在 Linux 系统中"一切皆文件",Linux 命令也不例外.那么,当编辑完成 Linux 命令并回车后,系统底层到底发生了什么事情呢? 简单来说,Linux 命令的执 ...