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(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...
随机推荐
- Spring Boot 3.0.0 发布第一个里程碑版本M1,你的 Java 升到17 了吗?
2022年1月20日,Spring官方发布了Spring Boot 3.0.0的第一个里程碑版本M1. 下面一起来来看看Spring Boot 3.0.0 M1版本都有哪些重大变化: Java基线从 ...
- python中grpc配置asyncio使用
python中grpc配置asyncio使用 安装grpclib pip3 install grpclib protoc编译.proto文件,生成源码文件 python -m grpc_tools.p ...
- 负载均衡后端状态(proxy_next_upstream 后端错误标识)
目录 一:负载均衡后端状态 二:down(无论什么情况不会分配流量) 三:backup(备用只有当所有的机器宕机(关闭)才能启动备份服务器) 四:max_fails.fail_timeout(结合使用 ...
- 一起玩转玩转LiteOS组件:TinyFrame
摘要:TinyFrame是一个简单的用于解析串口(如 UART.telnet.套接字等)通信数据帧的库. 本文分享自华为云社区<LiteOS组件尝鲜-玩转TinyFrame>,作者:Lio ...
- Java多线程专题2: JMM(Java内存模型)
合集目录 Java多线程专题2: JMM(Java内存模型) Java中Synchronized关键字的内存语义是什么? If two or more threads share an object, ...
- libevent网络库
1.概述 libevent是一个C语言编写的.轻量级开源高性能事件通知库.作为底层网络库,已经被广泛应用(如:memcached.Vomit.Nylon.Netchat等).主要有以下几个亮点: 事件 ...
- 计算机网络再次整理————tcp例子[五]
前言 本文介绍一些tcp的例子,然后不断完善一下. 正文 服务端: // See https://aka.ms/new-console-template for more information us ...
- JQuery扩展方法实现Form表单与Json互相转换
1.把表单转换出json对象 //把表单转换出json对象 $.fn.toJson = function () { var self = this, json = {}, push_counters ...
- Junit4进行参数化测试
@RunWith, 当类被@RunWith注解修饰,或者类继承了一个被该注解修饰的类,JUnit将会使用这个注解所指明的运行器(runner)来运行测试,而不是JUnit默认的运行器. 要进行参数化测 ...
- DockerClient端与DockerDaemon的通信安全
DockerClient端与DockerDaemon的通信安全 容器的安全性问题的根源在于容器和宿主机共享内核.如果容器里的应用导致Linux内核崩溃,那么整个系统可能都会崩溃.与虚拟机是不同的,虚拟 ...