C#中的IDisposable模式用法詳解
本文實例講述了C#中IDisposable模式的用法,針對垃圾資源的回收進(jìn)行了較為詳細(xì)的講解。分享給大家供大家參考之用。具體方法如下:
首先,對于垃圾回收而言,在C#中,托管資源的垃圾回收是通過CLR的Garbage Collection來實現(xiàn)的,Garbage Collection會調(diào)用堆棧上對象的析構(gòu)函數(shù)完成對象的釋放工作;而對于一些非托管資源,比如數(shù)據(jù)庫鏈接對象等,需要實現(xiàn)IDisposable接口進(jìn)行手動的垃圾回收。那么什么時候使用Idisposable接口,以及如何使用呢?
先來參考一下如下代碼:
public interface IDisposable
{
void Dispose();
}
public class DisposablClass : IDisposable
{
//是否回收完畢
bool _disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~DisposableClass()
{
Dispose(false);
}
//這里的參數(shù)表示示是否需要釋放那些實現(xiàn)IDisposable接口的托管對象
protected virtual void Dispose(bool disposing)
{
if(_disposed) return; //如果已經(jīng)被回收,就中斷執(zhí)行
if(disposing)
{
//TODO:釋放那些實現(xiàn)IDisposable接口的托管對象
}
//TODO:釋放非托管資源,設(shè)置對象為null
_disposed = true;
}
}
Dispose()方法
當(dāng)需要回收非托管資源的DisposableClass類,就調(diào)用Dispoase()方法。而這個方法不會被CLR自動調(diào)用,需要手動調(diào)用。
~DisposableClass(),析構(gòu)函數(shù)
當(dāng)托管堆上的對象沒有被其它對象引用,GC會在回收對象之前,調(diào)用對象的析構(gòu)函數(shù)。這里的~DisposableClass()析構(gòu)函數(shù)的意義在于告訴GC你可以回收我,Dispose(false)表示在GC回收的時候,就不需要手動回收了。
虛方法Dispose(bool disposing)
通過此方法,所有的托管和非托管資源都能被回收。參數(shù)disposing表示是否需要釋放那些實現(xiàn)IDisposable接口的托管對象。
如果disposings設(shè)置為true,就表示DisposablClass類依賴某些實現(xiàn)了IDisposable接口的托管對象,可以通過這里的Dispose(bool disposing)方法調(diào)用這些托管對象的Dispose()方法進(jìn)行回收。
如果disposings設(shè)置為false,就表示DisposableClass類依賴某些沒有實現(xiàn)IDisposable的非托管資源,那就把這些非托管資源對象設(shè)置為null,等待GC調(diào)用DisposableClass類的析構(gòu)函數(shù),把這些非托管資源進(jìn)行回收。
另外,以上把Dispose(bool disposing)方法設(shè)置為protected virtual的原因是希望有子類可以一起參與到垃圾回收邏輯的設(shè)計,而且還不會影響到基類。比如有這樣的一個子類:
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ù)的時候回收
_disposed = true;
}
base.Dispose(disposing);//再調(diào)用父類的垃圾回收邏輯
}
}
在.NET 2.0之前,如果一個對象的析構(gòu)函數(shù)拋出異常,這個異常會被CLR忽略。但.NET 2.0以后,如果析構(gòu)函數(shù)拋出異常就會導(dǎo)致應(yīng)用程序的崩潰。所以,保證析構(gòu)函數(shù)不拋異常變得非常重要。
還有,Dispose()方法允許拋出異常嗎?答案是否定的。如果Dispose()方法有拋出異常的可能,那就需要使用try/catch來手動捕獲。以下是考慮Dispose()方法有異??赡艿膶懛ǎ?/p>
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)閉的時候可能會有異常
}
catch(Exception ex)
{
_log.Warn(ex);//記錄日志
try
{
_channelFactory.Abort();//丟棄的時候可能會有異常
}
catch(Exception cex)
{
_log.Warn(cex);//記錄日志
}
}
_channelFactory = null;
_disposed = true;
}
}
總結(jié):當(dāng)我們自定義的類及其業(yè)務(wù)邏輯中引用某些托管和非托管資源,就需要實現(xiàn)IDisposable接口,實現(xiàn)對這些資源對象的垃圾回收。
希望本文所述對大家實現(xiàn)高效率的C#程序設(shè)計能夠有所幫助。
相關(guān)文章
深入理解C# abstract和virtual關(guān)鍵字
深入理解C# abstract和virtual關(guān)鍵字,學(xué)習(xí)c#的朋友可以參考下。2011-06-06
C#實現(xiàn)文件與Base64的相互轉(zhuǎn)換
本文主要介紹了C#實現(xiàn)文件與Base64的相互轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Unity 通過LineRenderer繪制兩點(diǎn)之間的直線操作
這篇文章主要介紹了Unity 通過LineRenderer繪制兩點(diǎn)之間的直線操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
關(guān)于Unity C# Mathf.Abs()取絕對值性能測試詳解
這篇文章主要給大家介紹了關(guān)于Unity C# Mathf.Abs()取絕對值性能測試的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Unity C#具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04

