C#中的IDisposable模式
当谈到垃圾回收,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作;而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收。那么什么时候使用Idisposable接口,以及如何使用呢?
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的原因是希望有子类可以一起参与到垃圾回收逻辑的设计,而且还不会影响到基类。比如有这样的一个子类:
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()方法有异常可能的写法:
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.cnblogs.com/lori/p/3535470.html
http://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/
C#中的IDisposable模式的更多相关文章
- C#中对IDisposable接口的理解
http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html C#中对IDisposable接口的理解 本人最近接触一个项目,在这个项目里面看到很多类实现了 ...
- (转)MVC中的Repository模式
1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository. 2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名 ...
- MVC中的Repository模式
1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository. 2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名 ...
- C#中的IDisposable接口
深入理解C#中的IDisposable接口 写在前面 在开始之前,我们需要明确什么是C#(或者说.NET)中的资源,打码的时候我们经常说释放资源,那么到底什么是资源,简单来讲,C#中的每一种类型都是一 ...
- 【转】C#中对IDisposable接口的理解
IDisposable接口定义:定义一种释放分配的资源的方法. .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资 ...
- [转]改善C#程序的建议4:C#中标准Dispose模式的实现
需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不 ...
- 制作类似ThinkPHP框架中的PATHINFO模式功能
一.PATHINFO功能简述 搞PHP的都知道ThinkPHP是一个免费开源的轻量级PHP框架,虽说轻量但它的功能却很强大.这也是我接触学习的第一个框架.TP框架中的URL默认模式即是PathInfo ...
- 设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)
在前段时间呢陆陆续续的更新了一系列关于重构的文章.在重构我们既有的代码时,往往会用到设计模式.在之前重构系列的博客中,我们在重构时用到了“工厂模式”.“策略模式”.“状态模式”等.当然在重构时,有的地 ...
- 4.在MVC中使用仓储模式进行增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-using-the-repository-pattern-in-mvc/ 系列目录: ...
随机推荐
- Java 中判断字符串是否为空
public class TestString { public static void main(String[] args) { String abc = null; //先判断是否为null再判 ...
- POJ 1141 Brackets Sequence(括号匹配二)
题目链接:http://poj.org/problem?id=1141 题目大意:给你一串字符串,让你补全括号,要求补得括号最少,并输出补全后的结果. 解题思路: 开始想的是利用相邻子区间,即dp[i ...
- (二)HtmlUnit 使用
第一节: htmlunit 模拟浏览器请求 第二节: htmlunit 获取指定元素 第三节: htmlunit 使用代理 IP 第四节: htmlunit 取消 css,javascript 支持 ...
- Oracle学习笔记:实现select top N的方法
由于Oracle不支持select top N语句,所以在Oracle中需要利用order by和rownum的组合来实现select top N的查询. rownum是记录表中数据编号的一个隐藏字段 ...
- MySQL学习笔记:循环生成5万行id连续的数据
# ---- mysql循环生成5万行id连续的数据 ---- /* id 1 2 3 4 …… */ CREATE TABLE tb( id ) NOT NULL AUTO_INCREMENT, V ...
- CVE-2010-2883Adobe Reader和Acrobat CoolType.dll栈缓冲区溢出漏洞分析
Adobe Acrobat和Reader都是美国Adobe公司开发的非常流行的PDF文件阅读器. 基于Window和Mac OS X的Adobe Reader和Acrobat 9.4之前的9.x ...
- 《精通Python设计模式》学习行为型之责任链模式
感觉是全新的学习了. 因为在以前的工作中,并没有有意识的去运用哪一种编程模式. 以后要注意的了. 这才是高手之路呀~ class Event: def __init__(self, name): se ...
- Bridge 桥接
意图 将抽象部分与它的实现部分分离,使它们都可以独立地变化. 动机 当一个抽象可能有多个实现时,通常用继承来协调它们.抽象类定义对该抽象的接口,而具体的子类则用不同方式加以实现.但是此方法有时不够灵活 ...
- loadrunner录制时,设置能不记录所有的事件
loadrunner录制时,设置能不记录所有的事件 可以做如下两点设置: 1. 在record option下的recording选项卡下选择html advance,在script type下选择A ...
- Java 中的异常处理机制
生活中的异常: 不能够完整而顺利的完成一些工作 根据不同的异常进行相应的处理,而不会就此终端我们的生活 引出: 异常处理: 方式: 1.选择结构(逻辑判断)避免 demo:if逻辑处理异常 im ...