C#资源释放方法实例分析
作者:党校校长 发布时间:2022-03-22 04:46:20
本文实例讲述了C#资源释放方法。分享给大家供大家参考,具体如下:
1、try{}finally{}
2、using
只有类型实现了IDisposable接口并且重写Dispose()方法可以使用using语句实现资源释放.
首先来看MSDN中关于这个接口的说明:
[ComVisible(true)]
public interface IDisposable
{ // Methods
void Dispose();
}
1.[ComVisible(true)]:
指示该托管类型对 COM 是可见的.
2.此接口的主要用途是释放非托管资源。
当不再使用托管对象时,垃圾回收器会自动释放分配给该对象的内存。但无法预测进行垃圾回收的时间。另外,垃圾回收器对窗口句柄或打开的文件和流等非托管资源一无所知。将此接口的Dispose方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。
一、基本应用
1.我们来定义一个实现了IDisposable接口的类,代码如下:
public class TestClass :IDisposable
{
public void DoSomething()
{
Console.WriteLine("Do some thing....");
}
public void Dispose()
{
Console.WriteLine("及时释放资源");
}
}
2.我们有两种方式来调用:
2.1.第一种方式,使用Using语句会自动调用Dispose方法,代码如下:
using (TestClass testClass = new TestClass())
{
testClass.DoSomething();
}
2.2第二种方式,现实调用该接口的Dispose方法,代码如下:
TestClass testClass = new TestClass();
try {
testClass.DoSomething();
}
finally
{
IDisposable disposable = testClass as IDisposable;
if (disposable != null)
disposable.Dispose();
}
两种方式的执行结果是一样的。
2.3.使用try/catch/finally的好处是,捕获异常后可以进行处理与此同时也可以释放资源;但是使用using,有异常也可以释放资源,只是无法对异常进行处理,直接将异常放行,而已实际上这两种方法对资源的释放上是一样的.
二、Disposable 模式
1.在.NET种由于当对象变为不可访问后将自动调用Finalize方法,所以我们手动调用IDisposable接口的Dispose方法和对象终结器调用的方法极其类似,我们最好将他们放到一起来处理。
我们首先想到的是重写Finalize方法,如下:
protected override void Finalize()
{
Console.WritleLine("析构函数执行...");
}
当我们编译这段代码的时候,我们发现编译器会报如下的错误: 这是因为编译器彻底屏蔽了父类的Finalize方法,编译器提示我们如果要重写Finalize方法我们要提供一个析构函数来代替,下面我们就提供一个析构函数:
~TestClass() { Console.WriteLine("析构函数执行..."); }
实际上这个析构函数编译器会将其转变为如下代码:
protected override void Finalize()
{
try {
Console.WritleLine("析构函数执行...");
}
finally {
base.Finalize();
}
}
2.然后我们就可以将Dispose方法的调用和对象的终结器放在一起来处理,如下:
public class TestClass: IDisposable
{
~TestClass()
{
Dispose();
}
public void Dispose()
{ // 清理资源
}
}
3.上面实现方式实际上调用了Dispose方法和Finalize方法,这样就有可能导致做重复的清理工作,所以就有了下面经典Disposable 模式:
private bool _isDisposed = false;
public void Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}
protected void Dispose(bool Diposing)
{
if(!_isDisposed)
{
if(Disposing)
{
//清理托管资源
}
//清理非托管资源
}
_isDisposed=true;
}
~TestClass()
{
Dispose(false);
}
3.1. SupressFinalize方法以防止垃圾回收器对不需要终止的对象调用 Object.Finalize()。
3.2. 使用IDisposable.Dispose 方法,用户可以在可将对象作为垃圾回收之前随时释放资源。如果调用了 IDisposable.Dispose方法,此方法会释放对象的资源。这样,就没有必要进行终止。IDisposable.Dispose 应调用 GC.SuppressFinalize 以使垃圾回收器不调用对象的终结器。
3.3.我们不希望Dispose(bool Diposing)方法被外部调用,所以他的访问级别为protected 。如果Diposing为true则释放托管资源和非托管资源,如果 Diposing等于false则该方法已由运行库从终结器内部调用,并且只能释放非托管资源。
3.4.如果在对象被释放后调用其他方法,则可能会引发 ObjectDisposedException。
三、实例解析
1.下面代码对Dispose方法做了封装,说明如何在使用托管和本机资源的类中实现 Dispose(bool) 的常规示例:
public class BaseResource : IDisposable
{
// 非托管资源
private IntPtr _handle;
//托管资源
private Component _components;
// Dispose是否被调用
private bool _disposed = false;
public BaseResource() { }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
// 释放托管资源
_components.Dispose();
}
// 释放非托管资源,如果disposing为false, 只有非托管资源被释放
CloseHandle(_handle);
_handle = IntPtr.Zero;
// 注意这里不是线程安全的
}
_disposed = true;
}
// 析构函数只会在我们没有直接调用Dispose方法的时候调用
// 派生类中不用在次提供析构函数
~BaseResource() { Dispose(false); }
// 如果你已经调用了Dispose方法后再调用其他方法会抛出ObjectDisposedException
public void DoSomething()
{
if (this._disposed)
{
throw new ObjectDisposedException();
}
}
}
public class MyResourceWrapper : BaseResource
{
// 托管资源
private ManagedResource _addedManaged;
// 非托管资源
private NativeResource _addedNative;
private bool _disposed = false;
public MyResourceWrapper() { }
protected override void Dispose(bool disposing)
{
if (!this._disposed)
{
try
{
if (disposing)
{
_addedManaged.Dispose();
}
CloseHandle(_addedNative);
this._disposed = true;
}
finally
{
base.Dispose(disposing);
}
}
}
}
2.使用CLR垃圾收集器,您不必再担心如何管理对托管堆分配的内存,不过您仍需清理其他类型的资源。托管类通过IDisposable接口使其使用方可以在垃圾收集器终结对象前释放可能很重要的资源。通过遵循disposable模式并且留意需注意的问题,类可以确保其所有资源得以正确清理,并且在直接通过Dispose调用或通过终结器线程运行清理代码时不会发生任何问题。
希望本文所述对大家C#程序设计有所帮助。
猜你喜欢
- 一、前言ConcurrentHashMap的源码采用了一种比较独特的方式对map中的元素数量进行统计,自然是要好好研究一下其原理思想,同时也
- 1. 文件上传a. 看看@FIEL注解的属性/** * 上传文件时使用该注解 设置文件相关参数 */@Retention(Retention
- 1、前言最近在用Kotlin+Spring Boot写一个后端项目,实体类习惯性地用了Kotlin中的data class,但是Spring
- Java面向对象之猜拳游戏,供大家参考,具体内容如下1 要求与电脑进行猜拳并记录分数。2 Computer.java 源代码(电脑自动随机出
- 前言Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows
- DropDownList控件又称下拉列表框控件, 控件 列表 中的多行数 据 以隐含 的形式表 示 出 来,当用户需要选择所需列表项时,通过
- 前言最近因为同事bean配置的问题导致生产环境往错误的redis实例写入大量的数据,差点搞挂redis。经过快速的问题定位,发现是同事新增一
- 概述线程池的好处和使用本篇文章就不赘叙了,不了解的可以参考下面两篇文章:一文全貌了解线程池的正确使用姿势学习线程池原理从手写一个线程池开始那
- 最初,XML 语言仅仅是意图用来作为 HTML 语言的替代品而出现的,但是随着该语言的不断发展和完善,人们越来越发现它所具有的优点:例如标记
- 一、前言上一篇文章中我们已经Spring Boot 利用注解方式整合 MyBatis,今天我们就来看看,如何利
- 目录一、什么是Spring二、什么是IOC三、快速搭建框架环境四、spring之依赖注入五、详解Spring框架的IOC之注解方式七、Spr
- 序列化与反序列化序列化:把对象转换成字节的过程,称为对象序列化反序列化:把字节恢复成对象的过程,称为反序列化对象的持久化概念:把字节保存的硬
- 短网址应用已经在全国各大微博上开始流行了起来。例如QQ微博的url.cn,新郎的sinaurl.cn等。我们在QQ微博上发布网址的时候,微博
- 废话不多说了,直接给大家贴java代码了。具体代码如下所示:/*支付流程*//****Controller.java 代码如下:*/@Req
- 先扯再说最近一直在研究某个国产开源的MySQL数据库中间件,拉下其最新版的代码到eclipse后,启动起来,然后做各种测试和代码追踪;用完想
- 使用Mybatis-Plus的SqlSessionFactory问题前些日子工作中出现一个问题,项目中使用了MybatisPlus,然后出现
- Java异常是Java提供的一种识别及响应错误的一致性机制。Java异常机制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅
- 一.背景本文主要介绍Java 8中时间的操作方法java.util.Date是用于表示一个日期和时间的对象(注意与java.sql.Date
- Intellij IDEA 配置Subversion插件实现步骤详解在使用Intellij的过程中,突然发现svn不起效了,在VCS–》Ch
- 在使用Mybatis时,有的时候我们可以不用定义resultMap,而是直接在<select>语句上指定resultType。这