C#中的IDisposable模式用法详解

news/2024/7/7 9:58:56
篇文章主要介绍了C#中的IDisposable模式用法,讲述了垃圾资源回收机制的实现,并对比分析了Dispose()方法、~DisposableClass()析构函数、虚方法Dispose(bool disposing)的原理,需要的朋友可以参考下

本文实例讲述了C#中IDisposable模式的用法,针对垃圾资源的回收进行了较为详细的讲解。分享给大家供大家参考之用。具体方法如下:

首先,对于垃圾回收而言,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作;而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收。那么什么时候使用Idisposable接口,以及如何使用呢?

先来参考一下如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface IDisposable
{
   void Dispose();
}
public class DisposablClass : IDisposable
{
   //是否回收完毕
   bool _disposed;
   public void Dispose()
   {
     Dispose( true );
     GC.SuppressFinalize( this );
   }
   ~DisposableClass()
   {
     Dispose( false );
   }
   
   //这里的参数表示示是否需要释放那些实现IDisposable接口的托管对象
   protected virtual void Dispose( bool disposing)
   {
     if (_disposed) return ; //如果已经被回收,就中断执行
     if (disposing)
     {
       //TODO:释放那些实现IDisposable接口的托管对象
     }
     //TODO:释放非托管资源,设置对象为null
     _disposed = true ;
   }
}

Dispose()方法

当需要回收非托管资源的DisposableClass类,就调用Dispoase()方法。而这个方法不会被CLR自动调用,需要手动调用。

~DisposableClass(),析构函数

当托管堆上的对象没有被其它对象引用,GC会在回收对象之前,调用对象的析构函数。这里的~DisposableClass()析构函数的意义在于告诉GC你可以回收我,Dispose(false)表示在GC回收的时候,就不需要手动回收了。

虚方法Dispose(bool disposing)

通过此方法,所有的托管和非托管资源都能被回收。参数disposing表示是否需要释放那些实现IDisposable接口的托管对象。

如果disposings设置为true,就表示DisposablClass类依赖某些实现了IDisposable接口的托管对象,可以通过这里的Dispose(bool disposing)方法调用这些托管对象的Dispose()方法进行回收。

如果disposings设置为false,就表示DisposableClass类依赖某些没有实现IDisposable的非托管资源,那就把这些非托管资源对象设置为null,等待GC调用DisposableClass类的析构函数,把这些非托管资源进行回收。

另外,以上把Dispose(bool disposing)方法设置为protected virtual的原因是希望有子类可以一起参与到垃圾回收逻辑的设计,而且还不会影响到基类。比如有这样的一个子类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SubDisposableClass : DiposableClass
{
   private bool _disposed; //表示是否已经被回收
   protected override void Dispose( bool disposing)
   {
     if (!_disposed) //如果还没有被回收
     {
       if (disposiing) //如果需要回收一些托管资源
       {
         //TODO:回收托管资源,调用IDisposable的Dispose()方法就可以
       }
       //TODO:回收非托管资源,把之设置为null,等待CLR调用析构函数的时候回收
       _disposed = true ;
     }
     base .Dispose(disposing); //再调用父类的垃圾回收逻辑
   }
}

在.NET 2.0之前,如果一个对象的析构函数抛出异常,这个异常会被CLR忽略。但.NET 2.0以后,如果析构函数抛出异常就会导致应用程序的崩溃。所以,保证析构函数不抛异常变得非常重要

还有,Dispose()方法允许抛出异常吗?答案是否定的。如果Dispose()方法有抛出异常的可能,那就需要使用try/catch来手动捕获。以下是考虑Dispose()方法有异常可能的写法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class DisposableClass : IDisposable
{
   bool _disposed;
   ......
   protected virtual void Dispose( bool disposing)
   {
     if (_disposed) return ;
     if (disposing)
     {
       //TODO:调用托管资源的Dispose()方法进行垃圾回收
     }
     try
     {
       _channelFactory.Close(); //关闭的时候可能会有异常
     }
     catch (Exception ex)
     {
       _log.Warn(ex); //记录日志
       try
       {
         _channelFactory.Abort(); //丢弃的时候可能会有异常
       }
       catch (Exception cex)
       {
         _log.Warn(cex); //记录日志
       }
     }
     _channelFactory = null ;
     _disposed = true ;
   }
}

总结:当我们自定义的类及其业务逻辑中引用某些托管和非托管资源,就需要实现IDisposable接口,实现对这些资源对象的垃圾回收。


原文链接http://www.jb51.net/article/54899.htm


http://www.niftyadmin.cn/n/4204507.html

相关文章

java属于面相_Java面试笔试之面相对象技术(一)

一、基本概念1.1 面相对象的三大特性继承、封装、多态。(1)继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类…

vue中elementui command绑定变量对象方法

需求&#xff1a;点击下拉框&#xff0c;切换组&#xff0c;选中当前项 <el-dropdown trigger"click" class"child-controllerChild"command"(command) >handleDispatchTabClickBoxCommand(command)"><img class"child-iconAnd…

浮动图片(JS)

代码作用&#xff1a;鼠标上移到图片上时&#xff0c;图片浮动显现&#xff0c;就像是Apple的浮动菜单一样的效果。<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">&l…

vue组件和js实现鼠标悬停显示title效果

需求&#xff1a; 显示文本内容过长&#xff0c;显示…鼠标悬浮时&#xff0c;全部显示 使用element组件<el-tooltip offset"-2" class"item" effect"dark" placement"top"> <span class"dispatchSystemAddressBookIt…

java 判断以中文开始_java判断是否是中文字符

public class StringUtil {/*** 判断是否为中文字符* param c* return*/private static boolean isChinese(char c) {// GENERAL_PUNCTUATION 判断中文的“号// CJK_SYMBOLS_AND_PUNCTUATION 判断中文的。号// HALFWIDTH_AND_FULLWIDTH_FORMS 判断中文的&#xff0c;号Characte…

百度-相信中国-电子书-下载

/Files/dayouluo/相信中国.rar

JS之给元素添加类的方法

原生js中添加类的方法 //1.为 <div> 元素添加一个类: document.getElementById("div").classList.add("类名");//2.为 <div> 元素添加多个类: document.getElementById("div").classList.add("类名1","类名2",…

java中io操作详解_Java语言中的IO系统详解

Java语言中的IO系统Java的核心库java.io提供了全面的IO接口&#xff0c;包括&#xff1a;文件读写&#xff0c;标准设备输出等等。Java中IO是以流为基础进行输入输出的&#xff0c;所有数据被串行化写入输出流&#xff0c;或者从输入流读入。在具体使用中很多初学者对Java.io包…