程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Effective C#原則18:實現標准的處理(Dispose)模式(3)

Effective C#原則18:實現標准的處理(Dispose)模式(3)

編輯:關於C語言

如果派生類有另外 的清理任務,就讓它實現Dispose方法:

public class DerivedResourceHog : MyResourceHog
{
 // Have its own disposed flag.
 private bool _disposed = false;
 protected override void Dispose( bool isDisposing )
 {
  // Don't dispose more than once.
  if ( _disposed )
    return;
  if ( isDisposing )
  {
   // TODO: free managed resources here.
  }
  // TODO: free unmanaged resources here.
  // Let the base class free its resources.
  // Base class is responsible for calling
   // GC.SuppressFinalize( )
  base.Dispose( isDisposing );
  // Set derived class disposed flag:
  _disposed = true;
 }
}

注和意,派生類和基類都有一個處理狀態的標記, 這完全是被動的。重制的標記掩蓋了在處理時任何可能發生的錯誤,而且是單一 的類型處理,而不是處理構成這個對象的所有類型。(譯注:就是基類與子類各 自標記一個,互不影響。)

你應該被動的寫處理方法和析構函數,處理對 象可能以任何順序發生,你可能會遇到這種情況:你的類中某個成員在你調用 Dispose方法以前已經被處理過了。你沒有看到這種情況是因為Dispose()方法是 可以多次調用的。如果在一個已經被處理過的對象上調用該方法,就什麼也不發 生。析構函數也有同樣的規則。任何對象的引用存在於內存中時,你不用檢測 null引用。然而,你引用的對象可能已經處理掉了,或者它已經析構了。

這就引入用了一個非常重要的忠告:對於任何與處理和資源清理相關的 方法,你必須只釋放資源! 不要在處理過程中添加其它任何的任務。你在處理和 清理中添加其它任務時,可能會在對象的生存期中遇到一些嚴重而繁雜的問題。 對象在你創建它時出生,在垃圾回收器認領它時死亡。你可以認為當你的程序不 能再訪問它們時,它們是睡眠的。你無法訪問對象,無法調用對象的方法。種種 跡象表明,它們就像是死的。但對象在宣布死亡前,析構函數還有最後一氣。析 構函數什麼也不應該做,就是清理非托管資源。如果析構函數通過某些方法讓對 象又變得可訪問,那麼它就復活了。(譯注:析構函數不是用戶調用的,也不 由.Net系統調用,而是在由GC產生的額外線程上運行的) 它又活了,但這並不好 。即使是它是從睡眼中喚醒的。這裡有一個明顯的例子:

public class BadClass
{
 // Store a reference to a global object:
 private readonly ArrayList _finalizedList;
  private string _msg;
 public BadClass( ArrayList badList, string msg )
 {
  // cache the reference:
   _finalizedList = badList;
  _msg = (string)msg.Clone();
  }
 ~BadClass()
 {
  // Add this object to the list.
  // This object is reachable, no
  // longer garbage. It's Back!
  _finalizedList.Add( this );
 }
}

當一個BadClass對象的析構函數執行時,它把自己的一 個引用添加到了全局的鏈表中。這使得它自己又是可達的,它就又活了。前面向 你介紹的這個方法會遇到一些讓人畏縮的難題。對象已經被析構了,所以垃圾回 收器從此相信再也不用調用它的析構函數了。如果你實際要析構一個可達對象, 這將不會成功。其次,你的一些資源可能不再有用。GC不再從內存上移除那些只 被析構隊列引用的對象,但它們可能已經析構了。如果是這樣,它們很可能已經 不能使用了。(譯注:也就是說利用上面的那個方法讓對象復活後,很有可能對 象是不可用的。)盡管BadClass所擁有的成員還在內存裡,它們像是可以被析構 或者處理,但C#語言沒有一個方法可以讓你控制析構的次序,你不能讓這樣的結 構可靠的運行。不要嘗試。

我還沒有看到這樣的代碼:用這樣明顯的方 式來復活一個對象,除非是學術上的練習。但我看過這樣的代碼,析構函數試圖 完成一些實質的工作,最後還通過析構函數的調用把引用放到對象中,從而把自 己復活。析構函數裡面的代碼看上去是精心設計的,另外還有處理函數裡的。再 檢查一遍,這些代碼是做了其它事情,而不是釋放資源!這些行為會為你的應用 程序在後期的運行中產生很多BUG。刪除這些方法,確保析構函數和Dispose()方 法除了清理資源外,什麼也不做。

在托管環境裡,你不用為每一個創建 的類寫析構函數;只有須要釋放一些使用的非托管資源時才添加,或者你的類所 包含的成員有實現了IDisposable接口的時候也要添加。即使如此,你也只用實 現IDisposable接口完成所有的功能就行了,不用析構函數。否則,你會限制你 的派生類實現實現標准的Dispose習慣。 遵守這個我所講敘的標准的Dispose習 慣。這會讓你的程序生活變得輕松,也為你的用戶,也為那些從你的類創建派生 類的人。

返回教程目錄

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved