詳解c# 接口IDisposable的用法
C#的每一個(gè)類型都代表一種資源,而資源又分為兩類:
- 托管資源 由CLR管理分配和釋放的資源,即從CLR里new出來的對(duì)象。
- 非托管資源 不受CLR管理的對(duì)象,如Windows內(nèi)核對(duì)象,或者文件、數(shù)據(jù)庫(kù)連接、套接字、COM對(duì)象等。
如果類型用到了非托管資源,或者需要顯式釋放托管資源,那么需要讓類型繼承接口IDisposable。記?。喝绻愋托枰@式釋放資源,那么一定要繼承IDisposable接口。如:
class SampleClass:IDisposable
{
private IntPtr nativeResource = Marshal.AllocHGlobal(100);//非托管資源
private Bitmap bitmap = new Bitmap(100, 100);//托管資源
private bool isDisposed = false;
//實(shí)現(xiàn)IDisposable中的Dispose方法
public void Dispose( )
{
Dispose(true);
GC.SuppressFinalize(this);//通知垃圾回收器不用再調(diào)用終結(jié)器
}
//不必要的方法,只是為了符合其他語言的規(guī)范
public void Close()
{
Dispose();
}
//必須的,防止程序員忘記顯示調(diào)用Dispose方法(隱式清理)
~SampleClass()
{
Dispose(false);
}
//非密封類修飾用protected virtual,提醒子類必須實(shí)現(xiàn)自己的清理方法時(shí)注意到父類的清理工作
protected virtual void Dispose(bool isDisposing)
{
if(isDisposed)
{
return;
}
if(isDisposing)
{
//清理托管資源
if(bitmap != null)
{
bitmap.Dispose();
bitmap = null;
}
}
//清理非托管資源
if(nativeResource!=IntPtr.Zero)
{
Marshal.FreeHGlobal(nativeResource);
nativeResource = IntPtr.Zero;
}
isDisposed = false;
}
public void SamplePublicMethod()
{
if(isDisposed)
{
throw new ObjectDisposedException("SampleClass", "SampleClass is disposed");
}
//代碼
}
}
繼承IDisposable接口,可以使用using語法糖。在using語句代碼塊內(nèi),可以使用聲明的對(duì)象,當(dāng)語句離開代碼塊后,系統(tǒng)自動(dòng)釋放資源:
//使用using方法,當(dāng)語句離開代碼塊后,using內(nèi)的對(duì)象自動(dòng)釋放
using (SampleClass sample = new SampleClass())
{
//……
}
//以上代碼相當(dāng)于下面的代碼
SampleClass sample0 = new SampleClass();
try
{
//……
}
finally
{
sample0.Dispose();
}
在SampleClass中,存在一個(gè)終結(jié)器(C++中叫析構(gòu)器)。其意義在于,調(diào)用者可能并不會(huì)主動(dòng)調(diào)用Dispose方法,而終結(jié)器會(huì)被垃圾回收器調(diào)用調(diào)用,所以它作為釋放資源的補(bǔ)救措施。
在CLR中,每new一個(gè)對(duì)象時(shí),就會(huì)為該對(duì)象在堆上分配內(nèi)存,如果不再被引用,就會(huì)回收它們的內(nèi)存。如果沒有實(shí)現(xiàn)IDisposable接口的類型對(duì)象,垃圾回收器會(huì)直接釋放對(duì)象所占內(nèi)存;如果實(shí)現(xiàn)了,每次創(chuàng)建對(duì)象時(shí),CLR會(huì)將該對(duì)象的一個(gè)指針放到終結(jié)列表中,垃圾回收器在回收對(duì)象前會(huì)首先將終結(jié)列表中的指針放入一個(gè)freachable隊(duì)列。同時(shí),CLR會(huì)分配一個(gè)線程管理freachable隊(duì)列,調(diào)用對(duì)象終結(jié)器,只有此時(shí),對(duì)象才會(huì)被真正標(biāo)識(shí)為垃圾,并在下一次進(jìn)行垃圾回收時(shí)釋放對(duì)象所占內(nèi)存。即:實(shí)現(xiàn)IDisposable接口的類型,至少要經(jīng)過兩次垃圾回收才能真正釋放掉內(nèi)存。其中Dispose方法中的GC.SuppressFinalize()方法用于在顯示釋放資源后,通知垃圾回收器不用再調(diào)用終結(jié)器(隱式回收)釋放資源。
在實(shí)現(xiàn)IDisposable接口時(shí),其Dispose()方法并沒有做實(shí)際的清理工作,但提供了帶bool參數(shù)的受保護(hù)的虛方法。因?yàn)樵擃愋涂赡鼙黄渌惱^承,如果子類實(shí)現(xiàn)自己的Dispose模式,受保護(hù)的虛方法可以提醒子類:在實(shí)現(xiàn)自己的清理方法時(shí),需要注意父類的清理工作(base.Dispose方法)。
真正撰寫資源釋放代碼的虛方法有一個(gè)bool參數(shù),但是在顯示釋放資源(true)與隱式釋放資源(false)調(diào)用中傳入的參數(shù)不同。表明:隱式清理時(shí),只需要處理非托管資源就行。托管資源中的普通類型不需要手動(dòng)清理,而非普通類型需要手動(dòng)清理。
Dispose模式設(shè)計(jì)思路:如果調(diào)用者顯示調(diào)用了Dispose方法,那么類型按部就班釋放自己的全部資源,然后通知垃圾回收器不需要再釋放(GC.SuppressFinalize()方法);而忘記調(diào)用Dispose方法,那么類型就假定自己的所有托管資源會(huì)全部交給垃圾回收器回收,不需要手動(dòng)清理。
以上就是詳解c# 接口IDisposable的用法的詳細(xì)內(nèi)容,更多關(guān)于c# 接口IDisposable的用法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
簡(jiǎn)單的excel導(dǎo)入導(dǎo)出示例分享
這篇文章主要介紹了簡(jiǎn)單的excel導(dǎo)入導(dǎo)出示例分享,需要的朋友可以參考下2014-03-03
C#中判斷、驗(yàn)證字符串是否為日期格式的實(shí)現(xiàn)代碼
這篇文章主要介紹了C#中判斷、驗(yàn)證字符串是否為日期格式的實(shí)現(xiàn)代碼,使用DateTime類中自帶的兩個(gè)方法實(shí)現(xiàn),需要的朋友可以參考下2014-08-08
C#中JavaScriptSerializer幫助類用法實(shí)例
這篇文章主要介紹了C#中JavaScriptSerializer幫助類用法,實(shí)例分析了JavaScriptSerializer幫助類處理json字符串時(shí)的技巧,需要的朋友可以參考下2014-12-12
C#中正則表達(dá)式(Regex)過濾內(nèi)容的基本使用方法
在 Regex 類中提供了很多方法來操作正則表達(dá)式,這篇文章主要給大家介紹了關(guān)于C#中正則表達(dá)式(Regex)過濾內(nèi)容的基本使用方法,需要的朋友可以參考下2022-08-08
C#?wpf定義ViewModelBase進(jìn)行簡(jiǎn)化屬性綁定
綁定機(jī)制是wpf的核心,也是界面獨(dú)立的根本,尤其是使用了mvvm模式,本文主要介紹了wpf如何定義ViewModelBase進(jìn)行簡(jiǎn)化屬性綁定,需要的可以參考下2024-04-04
C#實(shí)現(xiàn)Word轉(zhuǎn)換RTF的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)Word轉(zhuǎn)換RTF,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12

