IDisposable?释放非托管资源接口
原文:https://www.cnblogs.com/luminji/archive/2011/03/29/1997812.html
IDisposable高级篇:https://docs.microsoft.com/zh-cn/dotnet/standard/garbage-collection/implementing-dispose
需要明确一下C#程序(或者说.NET)中的资源。简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类:
托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象;
非托管资源:不受CLR管理的对象,windows内核对象,如文件、数据库连接、套接字、COM对象、stream 流等;IDisposable仅当类型直接使用非托管资源时,才应实现
毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口IDisposable。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的Dispose方法。IDisposable接口:定义一种释放分配的资源的方法。
一、IDisposable的接口定义如下
public interface IDisposable
{
// Summary:
// Performs application-defined tasks associated with freeing, releasing, or
// resetting unmanaged resources.
void Dispose();
}
using 语句定义一个范围,在此范围的末尾将释放非托管资源对象。
二:IDisposable基本应用
1.下面的示例演示如何创建实现接口的资源类 IDisposable
using System;
using System.ComponentModel; // The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method. public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false; // The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
} // Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);//通知垃圾回收器不再调用终结器
}
//Dispose
方法执行所有对象清理,使垃圾回收器不再需要调用对象的 Object.Finalize 重写。 因此,调用 SuppressFinalize 方法会阻止垃圾回收器运行终结器。 如果类型没有终结器,则对 GC.SuppressFinalize 的调用不起作用。 请注意,实际清除由Dispose(bool)
方法重载执行。 protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
} // Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero; // Note disposing has been done.
disposed = true;
}
} // Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle); // Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
//~MyResource()是析构函数,这边是假设使用非托管代码时候忘记释放资源,才会用到析构函数释放资源。析构函数本身就是负释非托管放资源的,因此不用再使用Dispose()函数再释放一次资源,因此给传给Dispose false参数。
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);//用到终结器 就是说以忘记了调用Dispose(true)释放资源了。Dispose(false)= Dispose(忘记)
}
}
public static void Main()
{
// Insert code here to create
// and use the MyResource object.
}
}
2、两种方式来调用
第一种:使用using 语句,则可以使用它,而无需显式调用 IDisposable.Dispose 自己。
using语句实际上是语法糖。 在编译时,语言编译器将为块实现中间语言 (IL) try / finally 。
using System;
using System.IO;
using System.Text.RegularExpressions; public class WordCount
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b"; public WordCount(string filename)
{
if (! File.Exists(filename))
throw new FileNotFoundException("The file does not exist."); this.filename = filename;
string txt = String.Empty;
using (StreamReader sr = new StreamReader(filename)) {
txt = sr.ReadToEnd();
}
nWords = Regex.Matches(txt, pattern).Count;
} public string FullName
{ get { return filename; } } public string Name
{ get { return Path.GetFileName(filename); } } public int Count
{ get { return nWords; } }
}
//C#8.0以后 using var StreamReader sr = new StreamReader(filename);//表示在函数范围结束前调用Dispose()释放非托管资源
static int WriteLinesToFile(IEnumerable<string> lines)
{
using var file = new System.IO.StreamWriter("WriteLines2.txt");
int skippedLines = 0;
foreach (string line in lines)
{
if (!line.Contains("Second"))
{
file.WriteLine(line);
}
else
{
skippedLines++;
}
}
// Notice how skippedLines is in scope here.
return skippedLines;
// file is disposed here
}
第二种: try / finally显示的释放资源
using System;
using System.IO;
using System.Text.RegularExpressions; public class WordCount
{
private String filename = String.Empty;
private int nWords = 0;
private String pattern = @"\b\w+\b"; public WordCount(string filename)
{
if (! File.Exists(filename))
throw new FileNotFoundException("The file does not exist."); this.filename = filename;
string txt = String.Empty;
StreamReader sr = null;
try {
sr = new StreamReader(filename);
txt = sr.ReadToEnd();
}
finally {
if (sr != null) sr.Dispose();
}
nWords = Regex.Matches(txt, pattern).Count;
} public string FullName
{ get { return filename; } } public string Name
{ get { return Path.GetFileName(filename); } } public int Count
{ get { return nWords; } }
}
出现无法无法调用的情况 Dispose
若要处理其无法调用的情况 Dispose ,您应该使用从派生的类 SafeHandle 来包装非托管资源,或者您应该 Object.Finalize (析构函数)为引用类型重写方法。 在任一情况下,使用方法可以在 Dispose 使用非托管资源(例如释放、释放或重置非托管资源)后执行任何需要的清理。
IDisposable 和继承层次结构
//注意:基类型不应包括任何Finalize终结器 (析构函数)
具有应可释放的子类的基类必须 IDisposable 按如下方式实现。 在 IDisposable sealed
Visual Basic) 中未 (的任何类型上实现时,应该使用此模式 NotInheritable
。
它应提供一个公共、非虚拟 Dispose() 方法和受保护的虚拟
Dispose(Boolean disposing)
方法。Dispose()方法必须调用
Dispose(true)
,并且应禁止终止以提高性能。基类型不应包括任何终结器。
下面的代码段反映了基类的释放模式。 它假定您的类型不重写 Object.Finalize 方法。
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices; class BaseClass : IDisposable
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true); // Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);//通知垃圾回收器不再调用终结器
} // Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return; if (disposing) {
handle.Dispose();
// Free any other managed objects here.
//
} disposed = true;
}
}
子类应实现以下可释放模式:
它们必须重写
Dispose(Boolean)
并调用基类Dispose(Boolean)
实现。如果需要,他们可以提供终结器。 终结器必须调用
Dispose(false)
。
请注意,派生类本身并不实现 IDisposable 接口,并且不包含无参数 Dispose 方法。 它们仅重写基类 Dispose(Boolean)
方法。
下面的代码段反映派生类的释放模式。 它假定您的类型不重写 Object.Finalize 方法。
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices; class DerivedClass : BaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true); // Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return; if (disposing) {
handle.Dispose();
// Free any other managed objects here.
//
} // Free any unmanaged objects here.
// disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
IDisposable?释放非托管资源接口的更多相关文章
- 5.C#释放非托管资源1
释放非托管资源 在介绍释放非托管资源的时候,我觉得有必要先来认识一下啥叫非托管资源,既然有非托管资源,肯定有托管资源. 托管资源指的是.net可以自棕进行回收的资源,主要是指托管堆上分配的内存资源.托 ...
- C#编程(七十四)----------释放非托管资源
释放非托管资源 在介绍释放非托管资源的时候,我觉得有必要先来认识一下啥叫非托管资源,既然有非托管资源,肯定有托管资源. 托管资源指的是.net可以自棕进行回收的资源,主要是指托管堆上分配的内存资源.托 ...
- [转]在C#中使用托管资源和非托管资源的区别,以及怎样手动释放非托管资源:
托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回 ...
- C# 释放非托管资源
C#中资源分为托管资源和非托管资源. 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放). 非托管资源需要自己编写代码来释放.那么编写好的释放非托管资源的代码(释非 ...
- 6.C# 释放非托管资源2
C# 释放非托管资源 C#中资源分为托管资源和非托管资源. 托管资源由垃圾回收器控制如何释放,不需要程序员过多的考虑(当然也程序员也可以自己释放). 非托管资源需要自己编写代码来释放.那么编写好的释放 ...
- Dispose模式释放非托管资源
实现方式用的是设计模式里的模板模式,基类先搭好框架,子类重写void Dispose(bool disposing) 即可. 需要注意的是基类的Finalize函数也就是析构函数调用的是虚函数void ...
- 利用IDisposable接口构建包含非托管资源对象
托管资源与非托管资源 在.net中,对象使用的资源分为两种:托管资源与非托管资源.托管资源由CLR进行管理,不需要开发人员去人工进行控制,.NET中托管资源主要指"对象在堆中的内存" ...
- SQL 横转竖 、竖专横 (转载) 使用Dapper.Contrib 开发.net core程序,兼容多种数据库 C# 读取PDF多级书签 Json.net日期格式化设置 ASPNET 下载共享文件 ASPNET 文件批量下载 递归,循环,尾递归 利用IDisposable接口构建包含非托管资源对象 《.NET 进阶指南》读书笔记2------定义不可改变类型
SQL 横转竖 .竖专横 (转载) 普通行列转换 问题:假设有张学生成绩表(tb)如下: 姓名 课程 分数 张三 语文 74 张三 数学 83 张三 物理 93 李四 语文 74 李四 数学 84 ...
- .net 资源释放(托管资源和非托管资源)
1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...
随机推荐
- Cesium入门6 - Adding Imagery - 添加图层
Cesium入门6 - Adding Imagery - 添加图层 Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com ...
- fidder无法下载证书的最佳解决办法
为什么有的小伙伴安装fidder不好使,手机无法下载证书? 1.安装一定要去官网安装! 一定要去官网安装! 一定要去官网安装!官方网址:https://www.telerik.com/download ...
- IoC容器-Bean管理(bean生命周期)
1,生命周期 即从对象创建到对象销毁的过程 2,bean生命周期 (1)通过构造器创建bean实例(无参数构造) (2)为bean的属性设置值和对其他bean的引用(调用set方法) (3)调用bea ...
- linux解析映射文件与自动加载脚本
目录 一 :解析映射文件 1.解析文件的由来之主机名: 2.解析映射文件(DNS) 二:磁盘挂载文件 三:开机自动加载脚本 一 :解析映射文件 1.解析文件的由来之主机名: 无论是在局域网还是在INT ...
- 布客·ApacheCN 编程/后端/大数据/人工智能学习资源 2020.7
公告 我们的群共享文件有备份到 IPFS 的计划,具体时间待定. 我们的机器学习群(915394271)正式改名为财务提升群,望悉知. 请关注我们的公众号"ApacheCN",回复 ...
- HowToDoInJava 其它教程 2 · 翻译完毕
原文:HowToDoInJava 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. ApacheCN 学习资源 目录 JMS 教程 JMS 教 ...
- Git .gitignore 不起作用的解决办法
解决方法的原理:.gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改.gitignore是无效的. 解决方案:git rm -r --cached . ...
- Linux中Swap与Memory内存简单介绍 (转)
https://blog.csdn.net/zwan0518/article/details/12059213 一.背景介绍 对于Linux来说,其在服务器市场的使用已经占据了绝对的霸主地位,不可动摇 ...
- Base64补充
1.Base64简单说明 描述:Base64可以成为密码学的基石,非常重要. 特点:可以将任意的二进制数据进行Base64编码 结果:所有的数据都能被编码为并只用65个字符就能表示的文本文件. 65字 ...
- VC中如何将资源打包并释放到指定文件夹
转载请注明来源:https://www.cnblogs.com/hookjc/ 很多时候,我们可能要将某些文件打包到资源中,然后当程序执行的时候,发现缺少某些文件时,进行自我修复,以维持程序的正常执行 ...