C#中的IDisposable模式用法詳解
本文實(shí)例講述了C#中IDisposable模式的用法,針對(duì)垃圾資源的回收進(jìn)行了較為詳細(xì)的講解。分享給大家供大家參考之用。具體方法如下:
首先,對(duì)于垃圾回收而言,在C#中,托管資源的垃圾回收是通過CLR的Garbage Collection來實(shí)現(xiàn)的,Garbage Collection會(huì)調(diào)用堆棧上對(duì)象的析構(gòu)函數(shù)完成對(duì)象的釋放工作;而對(duì)于一些非托管資源,比如數(shù)據(jù)庫鏈接對(duì)象等,需要實(shí)現(xiàn)IDisposable接口進(jìn)行手動(dòng)的垃圾回收。那么什么時(shí)候使用Idisposable接口,以及如何使用呢?
先來參考一下如下代碼:
public interface IDisposable { void Dispose(); } public class DisposablClass : IDisposable { //是否回收完畢 bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~DisposableClass() { Dispose(false); } //這里的參數(shù)表示示是否需要釋放那些實(shí)現(xiàn)IDisposable接口的托管對(duì)象 protected virtual void Dispose(bool disposing) { if(_disposed) return; //如果已經(jīng)被回收,就中斷執(zhí)行 if(disposing) { //TODO:釋放那些實(shí)現(xiàn)IDisposable接口的托管對(duì)象 } //TODO:釋放非托管資源,設(shè)置對(duì)象為null _disposed = true; } }
Dispose()方法
當(dāng)需要回收非托管資源的DisposableClass類,就調(diào)用Dispoase()方法。而這個(gè)方法不會(huì)被CLR自動(dòng)調(diào)用,需要手動(dòng)調(diào)用。
~DisposableClass(),析構(gòu)函數(shù)
當(dāng)托管堆上的對(duì)象沒有被其它對(duì)象引用,GC會(huì)在回收對(duì)象之前,調(diào)用對(duì)象的析構(gòu)函數(shù)。這里的~DisposableClass()析構(gòu)函數(shù)的意義在于告訴GC你可以回收我,Dispose(false)表示在GC回收的時(shí)候,就不需要手動(dòng)回收了。
虛方法Dispose(bool disposing)
通過此方法,所有的托管和非托管資源都能被回收。參數(shù)disposing表示是否需要釋放那些實(shí)現(xiàn)IDisposable接口的托管對(duì)象。
如果disposings設(shè)置為true,就表示DisposablClass類依賴某些實(shí)現(xiàn)了IDisposable接口的托管對(duì)象,可以通過這里的Dispose(bool disposing)方法調(diào)用這些托管對(duì)象的Dispose()方法進(jìn)行回收。
如果disposings設(shè)置為false,就表示DisposableClass類依賴某些沒有實(shí)現(xiàn)IDisposable的非托管資源,那就把這些非托管資源對(duì)象設(shè)置為null,等待GC調(diào)用DisposableClass類的析構(gòu)函數(shù),把這些非托管資源進(jìn)行回收。
另外,以上把Dispose(bool disposing)方法設(shè)置為protected virtual的原因是希望有子類可以一起參與到垃圾回收邏輯的設(shè)計(jì),而且還不會(huì)影響到基類。比如有這樣的一個(gè)子類:
public class SubDisposableClass : DiposableClass { private bool _disposed; //表示是否已經(jīng)被回收 protected override void Dispose(bool disposing) { if(!_disposed) //如果還沒有被回收 { if(disposiing) //如果需要回收一些托管資源 { //TODO:回收托管資源,調(diào)用IDisposable的Dispose()方法就可以 } //TODO:回收非托管資源,把之設(shè)置為null,等待CLR調(diào)用析構(gòu)函數(shù)的時(shí)候回收 _disposed = true; } base.Dispose(disposing);//再調(diào)用父類的垃圾回收邏輯 } }
在.NET 2.0之前,如果一個(gè)對(duì)象的析構(gòu)函數(shù)拋出異常,這個(gè)異常會(huì)被CLR忽略。但.NET 2.0以后,如果析構(gòu)函數(shù)拋出異常就會(huì)導(dǎo)致應(yīng)用程序的崩潰。所以,保證析構(gòu)函數(shù)不拋異常變得非常重要。
還有,Dispose()方法允許拋出異常嗎?答案是否定的。如果Dispose()方法有拋出異常的可能,那就需要使用try/catch來手動(dòng)捕獲。以下是考慮Dispose()方法有異常可能的寫法:
public class DisposableClass : IDisposable { bool _disposed; ...... protected virtual void Dispose(bool disposing) { if(_disposed) return; if(disposing) { //TODO:調(diào)用托管資源的Dispose()方法進(jìn)行垃圾回收 } try { _channelFactory.Close(); //關(guān)閉的時(shí)候可能會(huì)有異常 } catch(Exception ex) { _log.Warn(ex);//記錄日志 try { _channelFactory.Abort();//丟棄的時(shí)候可能會(huì)有異常 } catch(Exception cex) { _log.Warn(cex);//記錄日志 } } _channelFactory = null; _disposed = true; } }
總結(jié):當(dāng)我們自定義的類及其業(yè)務(wù)邏輯中引用某些托管和非托管資源,就需要實(shí)現(xiàn)IDisposable接口,實(shí)現(xiàn)對(duì)這些資源對(duì)象的垃圾回收。
希望本文所述對(duì)大家實(shí)現(xiàn)高效率的C#程序設(shè)計(jì)能夠有所幫助。
相關(guān)文章
C#中DataGridView常用操作實(shí)例小結(jié)
這篇文章主要介紹了C#中DataGridView常用操作,以實(shí)例形式總結(jié)了DataGridView綁定下拉列表、設(shè)置默認(rèn)值、判斷復(fù)選框是否選中等技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09C#實(shí)現(xiàn)chart控件動(dòng)態(tài)曲線繪制
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)chart控件動(dòng)態(tài)曲線繪制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02C# WinForm程序處理后臺(tái)繁忙導(dǎo)致前臺(tái)控件假死現(xiàn)象解決方法
這篇文章主要介紹了C# WinForm程序處理后臺(tái)繁忙導(dǎo)致前臺(tái)控件假死現(xiàn)象解決方法,本文通過Application.DoEvents()解決這個(gè)問題,并講解了Application.DoEvents()的作用,需要的朋友可以參考下2015-06-06C#實(shí)現(xiàn)動(dòng)態(tài)加載dll的方法
這篇文章主要介紹了C#實(shí)現(xiàn)動(dòng)態(tài)加載dll的方法,涉及針對(duì)動(dòng)態(tài)鏈接庫的靈活操作技巧,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2014-12-12