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(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...
随机推荐
- rpc基础讲解
什么是RPC 本地过程调用 远程过程调用带来的3个问题 RPC的调用过程 RPC的具体过程如下 总结 RPC.HTTP.Restful之间的区别 通过httpserver实现rpc 首先一点需要明确: ...
- 集合框架-工具类-Collection-toArray方法
1 package cn.itcast.p3.toolclass.arrays.demo; 2 3 import java.util.ArrayList; 4 import java.util.Arr ...
- Java 实现订单未支付超时自动取消
在电商上购买商品后,如果在下单而又没有支付的情况下,一般提示30分钟完成支付,否则订单自动.比如在京东下单为完成支付: 超过24小时,就会自动取消订单,下面使用 Java 定时器实现超时取消订单功能. ...
- jsp中获取下拉框的value问题
遇到问题 最近快期末考试了,今天想写一个简单的增删改查项目练练手,可是在刚写增加的时候就出现了问题,"增"一直是最简单的操作,本来自付很快就能写完,可是数据库中对应的下拉框数据一直 ...
- MySQL基本数据类型之枚举与集合类型
目录 一:枚举 1.枚举 2.创建表(使用枚举) 3.表内添加数据 二:集合 1.集合 2.创建表(使用集合) 3.表内添加数据 一:枚举 1.枚举 枚举作用: 提前定义好数据之后 后续录入只能录定义 ...
- Vue3源码分析之微任务队列
参考资料:https://zh.javascript.info/microtask-queue#wei-ren-wu-dui-lie-microtaskqueue 简化版 Vue3 中的 微任务队列实 ...
- JavaIo流入门篇之字节流基本使用。
一 基本知识了解( 字节流, 字符流, byte,bit是啥?) /* java中字节流和字符流之前有接触过,但是一直没有深入的学习和了解. 今天带着几个问题,简单的使用字节流的基本操作. 1 什么 ...
- 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)
无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...
- CNN-卷积神经网络简单入门(1)
卷积神经网络(Convolutional Neural Networks, CNN)是一类包含卷积计算且具有深度结构的前馈神经网络(Feedforward Neural Networks),是深度学习 ...
- Luogu P1314 [NOIP2011 提高组] 聪明的质监员
P1314 [NOIP2011 提高组] 聪明的质监员 题意 题目描述 给定\(n\)个物品,给定每个物品的 重量 \(w_i\) 和 价值 \(v_i\) 给定一个标准值 \(s\) 以及一个参数 ...