亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#中IDispose接口的實現及為何這么實現詳解

2019-10-29 21:02:20
字體:
來源:轉載
供稿:網友

前言

我原本認為對于IDispose的實現方法,只要在里面釋放非托管資源就行了,但是通過網上資料,看到很多實現方法并不是僅僅做釋放非托管資源,非常迷惑,關鍵是這些資料也沒詳細的告訴你為什么這么做?之后通過StackOverflow了解到這一步一步的原因,說的十分詳細,結合自己的認識,翻譯后分享給大家:

一、IDispose的實現方法

如果你能看懂,并且很清楚為什么那么做。那么以下的文章你就可以略去不看。如果不清楚為什么那么做,請帶著你的迷惑往下看:

二、為什么那樣實現

英文好的可以直接去StackOverflow原文地址:

https://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface/538238#538238

2.1、進行之前

在C++中,所有你在堆上申請的內存空間,必須手動釋放掉,否則就會造成內存的泄露。這可能會讓你在寫程序的時候要花點心思在內存的管理上而不是專注于解決你編程的目的—解決問題。所以作為C++的進化版C#使用了GC(Garbage Collector)來進行內存的管理以達到自動釋放不需要的內存的目的,但是GC并不能做的十分完美,對于一些非托管資源,GC無能為力,這就要求我們必須手動的釋放那么非托管資源,為了更好的去做到這一點,我們就要編寫一種方法,通過手動調用這個方法,我們就能夠釋放掉非托管資源。

注:

什么是托管資源和非托管資源?

托管資源就是托管給CLR的資源,CLR能對這些資源進行管理。而非托管資源則是CLR無法對這些資源管理,這些資源的申請、釋放必須由使用者自行管理。

例如,像Win32編程中的文件句柄,上下文句柄、窗口或網絡連接等資源都屬于非托管資源。但是如果這些非托管資源在.Net中進行了封裝,成為了.Net類庫中的一部分,它就不屬于非托管資源了,因為在對它們封裝的過程中,就實現了它們的自動管理功能。

也就是說,你能在.Net中找到的類產生的對象,都是托管資源。

(理解這點很重要,這可能是你看不懂上面實現教程的重要一個原因!)

注:

GC進行垃圾回收的時間和順序?

GC進行垃圾回收的時間我們根本無法確定(當然你手動調用GC的垃圾回收方法除外),并且順序也不能確定!也就是說,你先申請的空間有可能在你后申請的空間釋放之后釋放。

GC對于實現析構函數和沒實現析構函數的類處理方法不一樣,簡單些說GC對于實現了析構函數的類一定會調用他們的析構函數。

關于.Net的垃圾回收機制,你可以暫時先知道這么多,待看完了這篇文章再去深入了解。

2.2、我們需要編寫一種方法去釋放!

為了去清除一些非托管資源,你創建的類需要有一個public方法,方法的名字可以隨意命名

例如:

public void Cleanup() public void Shutdown() …… 

你可以這么做,但是有一個標準的名字

public void Dispose() 

甚至有一個接口IDisposeable,里面包含的就是剛才那個方法

public interface IDisposable {  void Dispose() } 

因此最好的辦法是讓你的類去實現IDisposable接口,在接口內的Dispose方法內提供一段清除非托管資源的代碼。

public void Dispose() {  //這里釋放一個句柄(句柄是一個非托管資源,屬于Win32編程的概念)  Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle); } 

OK。這就完成了,除非你想做的更好!

2.3、別忘了類中的托管資源還占著空間!

托管資源占著空間?你首先想到的可能是那些int,string等等這些托管資源,它們能占用幾個空間,他們占著就占著唄!

但是托管資源可不僅僅是那些資源,要是你的對象使用了250MB的System.Drawing,Bitmap(這是在.Net Frame中的,屬于托管資源)作為一些緩沖怎么辦?當然,你知道這是一個.Net的托管資源,所以GC理所應當的將會釋放它。但是你真的想留著250MB的內存空間就那么被占用著?然后等待著GC最終釋放它?更或者要是有一個更大數據庫連接呢?我們當然不想讓那連接白白占用來等待GC的終結!

如果用戶調用了Dispose方法(意味著他們不再想使用這個對象里的一切)為什么不去扔掉那些浪費空間的位圖資源和數據庫連接呢?

那么,我們就應該這么做:

  • 釋放非托管資源(因為我們必須這么做)
  • 釋放托管資源(讓你的Dispose更完美)

所以,讓我們更新我們的Dispose方法來釋放那些托管資源

public void Dispose() {  //Free unmanaged resources  Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);   //Free managed resources too  if (this.databaseConnection !=null)  {  this.databaseConnection.Dispose();  this.databaseConnection =null;  }  if (this.frameBufferImage !=null)  {  this.frameBufferImage.Dispose();  this.frameBufferImage = null;  } } 

OK,做的很好了,除非你想做的更好!

2.4、總會有人粗心忘記調用Dispose!

要是有人使用你的類創建了對象,但是忘記調用Dispose方法該怎么辦?這將會泄露一些非托管的資源!

注意:忘記調用Dispose方法雖然會造成非托管資源的泄露,但是對于那些托管資源來說,是不會泄露的,因為最終GC會行動起來,在后臺線程中釋放那些和托管資源有關的內存空間。這包括你創建的對象和其中的托管資源(例如Bitmap和數據庫連接) (為什么?往下看)

也就是說,如果你忘記調用Dispose方法,這個類應該自動進行一些補救措施!我們可以想到設計一種方法來做為一種后備方法:利用GC最終調用的終結器

注意:GC最終雖然會釋放托管資源,但是GC并不知道或者關心你的Dispose方法。那僅僅是一個我們選擇的名字。

GC調用析構函數是一個完美的時機來釋放托管資源,我們實現析構函數的功能通過重寫Finalize方法。

注意:在C#中,你不能真的去使用重寫虛函數的方法去重寫Finalize方法。你只能使用像C++的析構函數的語法去編寫,編譯器會自動對你的代碼進行一些改動來實現override終結器方法。(具體可查看MSDN中析構函數一節)

~MyObject() {  //we're being finalized (i.e.destroyed), call Dispose in case the user forgot to  Dispose(); //<--Warning:subtle bug! Keep reading! } 

但是這有一個Bug。

試想一下,你的GC是在后臺線程調用,你對GC的調用時間和對垃圾對象的釋放順序根本無法掌控,很有可能的發生的是,你的對象的某些托管資源已經在調用終結器之前就被釋放了,當GC調用終結器時,最終會釋放兩次托管資源!

public void Dispose() {  //Free unmanaged resources  Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);   //Free managed resources too  if (this.databaseConnection !=null)  {  this.databaseConnection.Dispose(); //<-- crash, GC already destroyedit  this.databaseConnection =null;  }  if (this.frameBufferImage !=null)  {  this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it  this.frameBufferImage = null;  } } 

所以你需要做的是讓終結器告訴Dispose方法,它不應該再次釋放任何托管資源了(因為這些資源很有可能已經被釋放了!)

標準的Dispose模式是讓Dispose函數和Finalize方法通過調用第三種方法,這個方法有一個bool類型的形參來表示此方法的調用是通過Dispose還是GC調用終結器。在這個方法里實現具體的釋放資源代碼。

這個第三種方法的命名當然可以隨意命名,但是規范的方法簽名是:

protected void Dispose(Boolean disposing) 

當然,這個參數的名字會讓人讀不懂什么意思。(很多網上教程都使用這個名字,第一次看很難看懂這個變量的作用)

這個參數也許可以這樣寫…

protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects) {  //Free unmanaged resources  Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);   //Free managed resources too, butonly if I'm being called from Dispose  //(If I'm being called fromFinalize then the objects might not exist  //anymore  if(itIsSafeToAlsoFreeManagedObjects)  {    if (this.databaseConnection !=null)   {   this.databaseConnection.Dispose();    this.databaseConnection =null;   }   if (this.frameBufferImage !=null)   {   this.frameBufferImage.Dispose();    this.frameBufferImage =null;   }  } } 

這樣IDisposable中的Dispose方法就變成了這樣:

public void Dispose() {  Dispose(true); //I am calling youfrom Dispose, it's safe } 

終結器就變成了這樣…

~MyObject() {  Dispose(false); //I am *not*calling you from Dispose, it's *not* safe } 

注意:你的類如果是從另一個類繼承而來,那么你不要忘記去調用父類的Dispose方法

public Dispose() {  try  {   Dispose(true); //true: safeto free managed resources  }  finally  {   base.Dispose();  } } 

所有的一切看起來都已經很好了,除非,你想做的更好!

2.5、最完美的方法?

如果使用者手動調用了Dispose方法,這樣,一切都被清空了。之后呢,因為你重寫了Finalize方法,GC一定調用這個方法,它將會再一次調用Dispose方法!

這不僅是一種性能上的浪費,而且關鍵是在Dispose方法調用后,那些引用已經變成了垃圾,GC會調用這些垃圾引用!

解決的方法是通過在Dispose方法中調用GC.SuppressFinalize() 來阻止GC去調用Finalize方法

public void Dispose() {  Dispose(true); //I am calling youfrom Dispose, it's safe  GC.SuppressFinalize(this); //Hey,GC: don't bother calling finalize later } 

這樣,每一件事都照顧到了!

(注:其實可以將Dispose(bool disposing)方法變成虛函數,如果你的類被繼承)

至此,我們一步一步實現了最好的IDisposable方法,現在回頭去看看一開始的實現IDisposable接口教程,是不是一切的透徹了?

三、使用終結器還是Dispose方法釋放非托管資源?

其實兩種方法都可以,但是就像在一開始提到的,GC的垃圾回收時間不確定,對于那些你已經不需要的資源,還是盡快釋放比較好,不應該總等著GC的垃圾回收,而且還有一個好處是,降低GC垃圾回收的時間,提高效率。何樂而不為呢?

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区视频在线播放| 亚洲精品456在线播放狼人| 日韩av在线天堂网| 欧美精品福利在线| 欧美午夜精品久久久久久浪潮| 色吧影院999| 国产精品嫩草影院久久久| 亚洲午夜精品久久久久久久久久久久| 国产精品久久久久久久久久| 欧美午夜视频在线观看| 九九综合九九综合| 国产日韩欧美夫妻视频在线观看| 亚洲欧美制服第一页| 欧美成人精品在线播放| 欧美日韩国产黄| 日韩电影免费在线观看| 国产精品成人免费电影| 国产精品久久久av久久久| 欧美成人午夜剧场免费观看| 欧美日韩亚洲网| 91美女福利视频高清| 国产suv精品一区二区| 国产精品第一页在线| 欧美日产国产成人免费图片| 国产一区二区三区在线视频| 午夜精品久久久久久久男人的天堂| 国产精品久久久久久久一区探花| 久久精品2019中文字幕| 国产精品偷伦免费视频观看的| 国产中文字幕日韩| 视频在线一区二区| 久久久亚洲欧洲日产国码aⅴ| 亚洲一区二区黄| 最近日韩中文字幕中文| 国产精品一区二区久久久久| www高清在线视频日韩欧美| 青青久久av北条麻妃海外网| 欧美在线观看日本一区| 国产精品久久不能| 亚洲第一国产精品| 秋霞午夜一区二区| 91av在线国产| 国产精品扒开腿做爽爽爽视频| 欧美日韩xxxxx| 欧美专区国产专区| 精品久久久久久中文字幕大豆网| 国产精品电影一区| 国产精品高潮视频| 欧美福利视频在线观看| 精品福利在线观看| 亚洲国产女人aaa毛片在线| 国产精品亚洲片夜色在线| 亚洲精品女av网站| 国产精品专区第二| 欧美成人午夜激情| 亚洲欧美国产va在线影院| 国产精品69久久久久| 精品国产一区二区三区在线观看| 亚洲综合国产精品| 国产视频欧美视频| 91av视频导航| 国产精品久久久亚洲| 粉嫩老牛aⅴ一区二区三区| 91免费人成网站在线观看18| 日本精品一区二区三区在线播放视频| 亚洲欧美日韩天堂一区二区| 欧美体内谢she精2性欧美| 亚洲第一男人av| 欧美另类暴力丝袜| 国产亚洲精品91在线| 一区二区欧美久久| 久久成人18免费网站| 97视频在线观看免费高清完整版在线观看| 日韩精品中文字| 久久综合色88| 国产亚洲精品美女久久久久| www.亚洲一二| 91精品国产高清久久久久久久久| 久久亚洲成人精品| 91情侣偷在线精品国产| www.欧美视频| 日韩电影大全免费观看2023年上| 456国产精品| 91精品视频免费| 91国产中文字幕| 亚洲电影免费观看高清完整版在线观看| 国产亚洲欧美aaaa| 久久久久久久久国产| 91精品一区二区| 欧美视频免费在线| 久久成人在线视频| 亚洲国产私拍精品国模在线观看| 欧美一级免费看| 欧美—级a级欧美特级ar全黄| 国产国语videosex另类| 成人性生交大片免费看视频直播| 精品视频久久久久久| 国产欧美日韩免费看aⅴ视频| 日韩精品视频三区| 国产美女精品免费电影| 久久99久国产精品黄毛片入口| 三级精品视频久久久久| 国产日韩欧美在线观看| 国产精品高潮呻吟久久av黑人| 色综合久久久888| 欧美黑人视频一区| 欧美性猛xxx| 国产精品91久久久| 久久亚洲精品毛片| 亚洲欧美色图片| 日韩欧美国产中文字幕| 亚洲精品视频二区| 亚洲网站在线播放| 亚洲japanese制服美女| 精品国产福利视频| 青草成人免费视频| 亚洲老头老太hd| 中文字幕视频在线免费欧美日韩综合在线看| 日韩免费中文字幕| 久久亚洲电影天堂| 国产精品2018| 欧美裸体xxxx极品少妇| 亚洲一区精品电影| 色先锋资源久久综合5566| 亚洲激情视频在线播放| 久久国产精品久久久久| 国产成人av在线播放| 欧美夜福利tv在线| 亚洲欧洲第一视频| 国产69精品99久久久久久宅男| 亚洲美女激情视频| 欧美一级淫片丝袜脚交| 66m—66摸成人免费视频| 91色视频在线观看| 成人天堂噜噜噜| 黑人巨大精品欧美一区二区免费| 国产在线观看91精品一区| 久久精品国产成人精品| 黄网站色欧美视频| 欧美一级bbbbb性bbbb喷潮片| 国产亚洲欧美aaaa| 91在线观看免费网站| 一区二区三区国产在线观看| 欧美三级欧美成人高清www| 日韩欧美成人精品| 欧美性资源免费| 日韩精品视频在线免费观看| 久久成人免费视频| 日韩av理论片| 日韩电视剧在线观看免费网站| 成人欧美一区二区三区在线| 久久免费成人精品视频| 亚洲人成电影网站| 98精品在线视频| 中文字幕自拍vr一区二区三区| 亚洲v日韩v综合v精品v| 91丨九色丨国产在线| 91精品国产色综合久久不卡98口| www国产亚洲精品久久网站| 亚洲女成人图区| 久久全球大尺度高清视频| 亚洲国产天堂久久国产91| 欧美日韩国产中文字幕| 精品在线观看国产|